实现方式
基础方式:有线程安全问题
private static LazySimpleSingletion instance;
private LazySimpleSingletion(){}
public static LazySimpleSingletion getInstance(){<br> //有线程安全问题,可以使用<br> if(instance == null){<br> instance = new LazySimpleSingletion();<br> }<br> return instance;<br>}
方法类锁:在公有方法上加锁,性能低
private static LazySimpleSingletion instance;
private LazySimpleSingletion(){}<br>
public synchronized static LazySimpleSingleton getInstance() {<br> if (instance == null) {<br> instance = new LazySimpleSingleton();<br> }<br> return instance;<br> }
双重检查锁:第一重判断提升性能,第二重判断保证单例
private volatile static LazyDoubleCheckSingleton instance;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance(){<br> //检查是否要阻塞,如果已经创建过,就不需要再进入加锁代码块拉低性能,大大的提升性能,如果<br>没有该检查,每次都会去竞争锁<br> if (instance == null) {<br> synchronized (LazyDoubleCheckSingleton.class) {<br> //检查是否要重新创建实例<br> //如果没有该判断,2个线程在第一个if都判断为null,那么就会创建2个实例<br> if (instance == null) {<br> instance = new LazyDoubleCheckSingleton();<br> }<br> }<br> }<br> return instance;<br>}
为什么要加volatile?
底层cpu优化,在不影响最终结果的时候,会进行指令重排。也就是说对象的实例化会在初始化之前执行。那么当另外的线程来判断第一个instance == null 不满足条件,但是对象还是一个没有初始化的对象。所以需要加volatile来禁止指令重排。
静态内部类
概念:双重检查锁有一定性能问题,那么我们还可以采用静态内部类的方式,该方式同样也是利用了类的加载机制,它与饿汉模式不同的是,它是在内部类里面去创建对象实例。这样的话,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。
private LazyStaticInnerClassSingleton(){<br> //解决反射破坏,因为反射可以调用私有的构造器<br> if(LazyHolder.INSTANCE != null){<br> throw new RuntimeException("不允许非法访问");<br> }<br>}
private static LazyStaticInnerClassSingleton getInstance(){<br> return LazyHolder.INSTANCE;<br>}
private static class LazyHolder{<br> private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton();<br>}