1.
//饿汉式单例 // 它是在类加载的时候就立即初始化,并且创建单例对象 //优点:没有加任何的锁、执行效率比较高, //在用户体验上来说,比懒汉式更好 //缺点:类加载的时候就初始化,不管你用还是不用,我都占着空间 //浪费了内存,有可能占着茅坑不拉屎 //绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题 public class HungrySingleton { //先静态、后动态 //先属性、后方法 //先上后下 private static final HungrySingleton hungrySingleton = new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){ return hungrySingleton; } }
//饿汉式静态块单例 public class HungryStaticSingleton { private static final HungryStaticSingleton hungrySingleton; static { hungrySingleton = new HungryStaticSingleton(); } private HungryStaticSingleton(){} public static HungryStaticSingleton getInstance(){ return hungrySingleton; } }
test
public class ConcurrentExecutor { /** * @param runHandler * @param executeCount 发起请求总数 * @param concurrentCount 同时并发执行的线程数 * @throws Exception */ public static void execute(final RunHandler runHandler,int executeCount,int concurrentCount) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); //控制信号量,此处用于控制并发的线程数 final Semaphore semaphore = new Semaphore(concurrentCount); //闭锁,可实现计数量递减 final CountDownLatch countDownLatch = new CountDownLatch(executeCount); for (int i = 0; i < executeCount; i ++){ executorService.execute(new Runnable() { public void run() { try{ //执行此方法用于获取执行许可,当总计未释放的许可数不超过executeCount时, //则允许同性,否则线程阻塞等待,知道获取到许可 semaphore.acquire(); runHandler.handler(); //释放许可 semaphore.release(); }catch (Exception e){ e.printStackTrace(); } countDownLatch.countDown(); } }); } countDownLatch.await();//线程阻塞,知道闭锁值为0时,阻塞才释放,继续往下执行 executorService.shutdown(); } public interface RunHandler{ void handler(); } }
2.
public class LazyDoubleCheckSingleton { private volatile static LazyDoubleCheckSingleton lazy = null; private LazyDoubleCheckSingleton(){} public static LazyDoubleCheckSingleton getInstance(){ if(lazy == null){ synchronized (LazyDoubleCheckSingleton.class){ if(lazy == null){ lazy = new LazyDoubleCheckSingleton(); //1.分配内存给这个对象 //2.初始化对象 //3.设置lazy指向刚分配的内存地址 //4.初次访问对象 } } } return lazy; } }
test
//懒汉式单例 //这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题 //完美地屏蔽了这两个缺点 //史上最牛B的单例模式的实现方式 public class LazyInnerClassSingleton { //默认使用LazyInnerClassGeneral的时候,会先初始化内部类 //如果没使用的话,内部类是不加载的 private LazyInnerClassSingleton(){ if(LazyHolder.LAZY != null){ throw new RuntimeException("不允许创建多个实例"); } } //每一个关键字都不是多余的 //static 是为了使单例的空间共享 //保证这个方法不会被重写,重载 public static final LazyInnerClassSingleton getInstance(){ //在返回结果以前,一定会先加载内部类 return LazyHolder.LAZY; } //默认不加载 private static class LazyHolder{ private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton(); } }
test
public class LazyInnerClassSingletonTest { public static void main(String[] args) { try{ //很无聊的情况下,进行破坏 Class<?> clazz = LazyInnerClassSingleton.class; //通过反射拿到私有的构造方法 Constructor c = clazz.getDeclaredConstructor(null); //强制访问,强吻,不愿意也要吻 c.setAccessible(true); //暴力初始化 Object o1 = c.newInstance(); //调用了两次构造方法,相当于new了两次 //犯了原则性问题, Object o2 = c.newInstance(); System.out.println(o1 == o2); // Object o2 = c.newInstance(); }catch (Exception e){ e.printStackTrace(); } } }
//懒汉式单例 //在外部需要使用的时候才进行实例化 public class LazySimpleSingleton { private LazySimpleSingleton(){} //静态块,公共内存区域 private static LazySimpleSingleton lazy = null; public synchronized static LazySimpleSingleton getInstance(){ if(lazy == null){ lazy = new LazySimpleSingleton(); } return lazy; } }
test
public class ExectorThread implements Runnable{ @Override public void run() { LazySimpleSingleton singleton = LazySimpleSingleton.getInstance(); // ThreadLocalSingleton singleton = ThreadLocalSingleton.getInstance(); System.out.println(Thread.currentThread().getName() + ":" + singleton); } }
public class LazySimpleSingletonTest { public static void main(String[] args) { Thread t1 = new Thread(new ExectorThread()); Thread t2 = new Thread(new ExectorThread()); t1.start(); t2.start(); System.out.println("End"); } }
3.
//Spring中的做法,就是用这种注册式单例 public class ContainerSingleton { private ContainerSingleton(){} private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>(); public static Object getInstance(String className){ synchronized (ioc) { if (!ioc.containsKey(className)) { Object obj = null; try { obj = Class.forName(className).newInstance(); ioc.put(className, obj); } catch (Exception e) { e.printStackTrace(); } return obj; } else { return ioc.get(className); } } } }
//常量中去使用,常量不就是用来大家都能够共用吗? //通常在通用API中使用 public enum EnumSingleton { INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance(){ return INSTANCE; } }
test
public class EnumSingletonTest { // public static void main(String[] args) { // try { // EnumSingleton instance1 = null; // // EnumSingleton instance2 = EnumSingleton.getInstance(); // instance2.setData(new Object()); // // FileOutputStream fos = new FileOutputStream("EnumSingleton.obj"); // ObjectOutputStream oos = new ObjectOutputStream(fos); // oos.writeObject(instance2); // oos.flush(); // oos.close(); // // FileInputStream fis = new FileInputStream("EnumSingleton.obj"); // ObjectInputStream ois = new ObjectInputStream(fis); // instance1 = (EnumSingleton) ois.readObject(); // ois.close(); // // System.out.println(instance1.getData()); // System.out.println(instance2.getData()); // System.out.println(instance1.getData() == instance2.getData()); // // }catch (Exception e){ // e.printStackTrace(); // } // } public static void main(String[] args) { try { Class clazz = EnumSingleton.class; Constructor c = clazz.getDeclaredConstructor(String.class,int.class); c.setAccessible(true); EnumSingleton enumSingleton = (EnumSingleton)c.newInstance("Tom",666); }catch (Exception e){ e.printStackTrace(); } } }
4.
//反序列化时导致单例破坏 public class SeriableSingleton implements Serializable { //序列化就是说把内存中的状态通过转换成字节码的形式 //从而转换一个IO流,写入到其他地方(可以是磁盘、网络IO) //内存中状态给永久保存下来了 //反序列化 //讲已经持久化的字节码内容,转换为IO流 //通过IO流的读取,进而将读取的内容转换为Java对象 //在转换过程中会重新创建对象new public final static SeriableSingleton INSTANCE = new SeriableSingleton(); private SeriableSingleton(){} public static SeriableSingleton getInstance(){ return INSTANCE; } private Object readResolve(){ return INSTANCE; } }
test
public class SeriableSingletonTest { public static void main(String[] args) { SeriableSingleton s1 = null; SeriableSingleton s2 = SeriableSingleton.getInstance(); FileOutputStream fos = null; try { fos = new FileOutputStream("SeriableSingleton.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s2); oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("SeriableSingleton.obj"); ObjectInputStream ois = new ObjectInputStream(fis); s1 = (SeriableSingleton)ois.readObject(); ois.close(); System.out.println(s1); System.out.println(s2); System.out.println(s1 == s2); } catch (Exception e) { e.printStackTrace(); } } }
5.
public class ThreadLocalSingleton { private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>(){ @Override protected ThreadLocalSingleton initialValue() { return new ThreadLocalSingleton(); } }; private ThreadLocalSingleton(){} public static ThreadLocalSingleton getInstance(){ return threadLocalInstance.get(); } }
test
public class ThreadLocalSingletonTest { public static void main(String[] args) { System.out.println(ThreadLocalSingleton.getInstance()); System.out.println(ThreadLocalSingleton.getInstance()); System.out.println(ThreadLocalSingleton.getInstance()); System.out.println(ThreadLocalSingleton.getInstance()); System.out.println(ThreadLocalSingleton.getInstance()); Thread t1 = new Thread(new ExectorThread()); Thread t2 = new Thread(new ExectorThread()); t1.start(); t2.start(); System.out.println("End"); } }
6.
public class Pojo { }
public class ContainerSingletonTest { public static void main(String[] args) { try { long start = System.currentTimeMillis(); ConcurrentExecutor.execute(new ConcurrentExecutor.RunHandler() { public void handler() { Object obj = ContainerSingleton.getInstance("com.gupaoedu.vip.pattern.singleton.test.Pojo");; System.out.println(System.currentTimeMillis() + ": " + obj); } }, 10,6); long end = System.currentTimeMillis(); System.out.println("总耗时:" + (end - start) + " ms."); }catch (Exception e){ e.printStackTrace(); } } }