美文网首页
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