美文网首页
BiBi - 并发编程 -7- DCL

BiBi - 并发编程 -7- DCL

作者: 奋飞的蜗牛ing | 来源:发表于2019-12-10 00:42 被阅读0次

    From:Java并发编程的艺术

    DCL实现单例
    public class Singleton {
    
        private volatile Singleton singleton;
        
        // 构造函数是private,防止外部实例化
        private Singleton() {}
        
        public static Singleton getInstance() {
            if (singleton == null) { // 第一次检查
                synchronized (Singleton.class) {
                    if (singleton == null) { // 第二次检查,"double check"的由来
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }
    

    Java中创建一个对象分为三个步骤:
    1)在内存中开辟一块地址
    2)对象初始化
    3)将指针指向这块内存地址
    Java中存在指令重排序现象。如果在新建Singleton对象的时候第2步和第3步发生了重排序,线程1将singleton指针指向了内存中的地址,但是此时我们的对象还没有初始化。这个时候线程2进来,看到singleton不是null,于是直接返回。这个时候错误就发生了,线程2拿到了一个没有经过初始化的对象。解决这个问题的思路也很简单,就是使用volatile防止指令重排序。

    内部类实现单例
    public class Singleton {    
        private Singleton(){}
        public static Singleton getInstance() {
            return SingletonHolder.singleton;
        }
        private static class SingletonHolder {
            private static Singleton singleton = new Singleton();
        }
    }
    

    基于ClassLoader的实现多线程同步,即利用classloder的机制来保证初始化instance时只有一个线程。JVM在类初始化阶段会获取一个锁,这个锁可以同步多个线程对同一个类的初始化。

    枚举实现单例
    public enum Singleton {
      instance;
      private Singleton(){}
      public void doSomething(){}
    }
    

    优点:线程安全、保证只有一个实例、能够实现反序列化。
    其它单例实现方式在反序列化时会通过【反射】去重新创建对象。若要避免需要手动实现private Object readResolve(){return singleton;}

    相关文章

      网友评论

          本文标题:BiBi - 并发编程 -7- DCL

          本文链接:https://www.haomeiwen.com/subject/kwwokqtx.html