Java中单列模式的写法

第一种 饿汉式
public class A {
    private static A a = new A();
    private A() {    }
    public static A getInstance() {
        return a;
    }
}

缺点: 类加载的时候就会初始化,没有有懒加载的效果

第二种 懒汉式
public class A {
    private static A a = null;
    private A() {    }
    public static synchronized A getInstance() {
        if (a == null) {
            a = new A();
        }
        return a;
    }
}

缺点: 每次调用方法都会去获取锁,影响性能

第三种 双从检查锁定和volatile (推荐)
public class A {
    private volatile static A a = null;   //   标注1
    private A() {    }
    public static A getInstance() {
        if (a == null) {            // 标注3
            synchronized (A.class) {
                if (a == null) {
                    a = new A();     // 标注2
                }
            }
        }
        return a;
    }
}

标注2 : new A() 这个操作会被翻译成三步执行,

  • memory = allocate(); //1. 分配对象的内存空间
  • ctorInstance(memory); //2. 初始化对象
  • instance = memory; //3. 设置instance指向刚分配的内存地址
    这三个操作中2,3 可能会被编译器或者处理器优化重新排序,先执行3,在执行2,那么如果同时有线程A 执行到了 标注3,线程B 执行到了标注2*,对于A 线程来说拿到的 a 引用不等于空,所以直接return

标注1: 为了解决上面的问题,加了volatile;禁止了重新排序,具体参考volatile的重新排序规则

第四种: 基于类初始化
public class A {
    private static class InstanceHolder {
        private static A a = new A();
    }
    public static A getInstance() {
        return InstanceHolder.a;   // 这里将导致InstanceHolder类被初始化
    }
}

JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在执行初始化期间,JVM会去获取一个锁。

image.png

你可能感兴趣的:(Java中单列模式的写法)