饿汉式
package com.dwz.concurrency2.chapter1; /** * 饿汉式 */ public class SingletonObject2 { /* * can't lazy load. */ private static final SingletonObject2 instance = new SingletonObject2(); private SingletonObject2() { //empty } public static SingletonObject2 getInstance() { return instance; } }
缺点:不能进行懒加载,可能会造成资源浪费
懒汉式
package com.dwz.concurrency2.chapter1; /** * 懒汉式(双重检查) */ public class SingletonObject1 { private static SingletonObject1 instance; private SingletonObject1() { //empty } //double check //解决了懒加载问题和线程安全问题 public static SingletonObject1 getInstance() { if(null == instance) { synchronized (SingletonObject1.class) { if(null == instance) { instance = new SingletonObject1(); } } } //会出现初始化异常问题,instance还在重排序,未初始化完成,此时已不是null,就被return return instance; } }
缺点:不能保证线程绝对安全,尤其是new SingletonObject1()中加载比较重的v资源时
介绍三种比较优雅的v单例模式:
1.双重检查改良版
package com.dwz.concurrency2.chapter1; /** * 懒汉式(双重检查-线程安全) */ public class SingletonObject3 { //volatile可以保证内存可见性,有序性,不让jvm自作主张去优化 //可以保证之前的写操作完成 private static volatile SingletonObject3 instance; private SingletonObject3() { //empty } //double check add volatile public static SingletonObject3 getInstance() { if(null == instance) { synchronized (SingletonObject3.class) { if(null == instance) { instance = new SingletonObject3(); } } } return instance; } }
缺点:虽然解决了线程安全问题,但是jvm的一些底层优化操作被摒弃
2.holder方式
package com.dwz.concurrency2.chapter1; /** * holder方式(推荐使用) * 懒加载、线程安全、效率高 */ public class SingletonObject4 { private SingletonObject4() { } private static class InstanceHolder { private final static SingletonObject4 instance = new SingletonObject4(); } public static SingletonObject4 getInstance() { return InstanceHolder.instance; } }
3.枚举法
package com.dwz.concurrency2.chapter1; import java.util.stream.IntStream; /** * 枚举法:(大师推荐) * 天生就是线程安全的,构造函数只被加载一次 */ public class SingletonObject5 { private SingletonObject5() { } private enum Singleton { INSTANCE; private final SingletonObject5 instance; Singleton() { instance = new SingletonObject5(); } public SingletonObject5 getInstance() { return instance; } } public static SingletonObject5 getInstance() { return Singleton.INSTANCE.getInstance(); } public static void main(String[] args) { IntStream.rangeClosed(1, 100) .forEach(i-> new Thread(String.valueOf(i)) { @Override public void run() { System.out.println(SingletonObject5.getInstance()); } }.start()); } }