单利的三种写法

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():

  1. 给ins分配内存
  2. 调用构造函数来初始化成员变量(可能会很久)
  3. 将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实例化之后就不需要同步了。

上一篇下一篇

猜你喜欢

热点阅读