单利的三种写法
2018-09-22 本文已影响23人
MDZZ灭顶之灾12138
double-check线程安全,适用于高并发。
public class DoubleCheck{
private volatile static DoubleCheck ins;
private DoubleCheck(){}
public static DoubleCheck getIns() {
if (null == ins) {
synchronized (DoubleCheck.class) {
if (null == ins) {
ins = new DoubleCheck();
}
}
}
return ins;
}
}
执行ins = new DoubleCheck():
- 给ins分配内存
- 调用构造函数来初始化成员变量(可能会很久)
- 将ins对象指向分配的内存空间(执行完这一步,ins才不为空)
以上的操作不是原子操作,jvm也可能重新排序指令,导致2,3步顺序可能会被打乱,,当第3步先于第2步完成,就会导致有的线程拿到了初始化未完毕的ins,就会出错。可以利用volatile禁止指令重新排序优化特性来解决。
饿汉式:
public class Early{
private Early(){}
private static final Early ins = new Early();
public static Early getIns() {
return ins;
}
内部类方式,比饿汉式更优秀,Effective Java 推荐
public class Singleton{
private Singleton(){}
private static class Holder {
private static final Singleton ins = new Singleton();
}
public static Singleton getIns() {
return Holder.ins;
}
}
经典模式:
public class Singleton{
private static Singleton ins;
private Singleton(){}
public static synchronized Singleton getIns() {
if (null == ins) {
ins = new Singleton();
}
return ins;
}
}
延迟实例化,节省资源。但是synchronized,每次调用getIns()都得同步,很消耗性能。只需在第一次执行的时候同步,当ins实例化之后就不需要同步了。