谈谈部分单例设计模式

饿汉模式

public class Singleton1 implements Serializable {
    private static Singleton1 instance = new Singleton1();
    private Singleton1(){

    }
    public static Singleton1 getInstance(){
        return instance;
    }
}

是怎么保证线程安全的?

线程安全的懒汉模式

双重检测锁(Double Checked Lock DCL) + volatitle

  • DCL,避免多个线程同时指执行到if(instance == null),判断都为true,会排队创新等待创建新对象
  • volatitle关键字 防止CPU指令重排,instance = new Singleton4()不是原子操作,会涉及三个步骤,CPU执行顺序有可能会乱(给实例分配内存空间;调用对象的构造方法,初始化成员字段;将instance 对象指向分配的内存空间)
public class Singleton4 {
    private volatile static Singleton4 instance;
    private Singleton4(){}
    public static Singleton4 getInstance(){
        if(instance == null){
            synchronized (Singleton4.class){
                if(instance == null){
                    instance = new Singleton4();
                }
            }
        }
        return instance;
    }
}

在第一次调用Singleton4.getInstance()的时候初始化静态变量
类并不是在加载完之后就会实例static变量。那到底什么时候才会初始化呢?

1.当遇到new,getstatic,putstatic或者invokestatic这四条字节码指令的时候,如果该类没有进行
初始化,则需要先初始化.这四条指令对应的是实例化对象,获取一个静态变量,设置一个静态变量(常量
放在常量池中,不会触发),或者调用静态方法的时候.
2.当时候反射包的方法对类进行反射调用的时候
3.当初始化一个类的时候,发现该类的父类还没有进行初始化,则初始其父类
4.当jvm启动的时候,当用户指定执行一个主类(就是包含main的那个类),虚拟机会先初始化这个类.

上述的例子是因为满足第一条,执行static方法的时候编译器会生成invokestatic指令,这时候instance没有初始化,所以会执行Instance的构造方法,然后在return返回。

静态内部类模式

public class Instance1 {
    private static class Holder{
        private static Instance1 instance = new Instance1();
    }
    private Instance1(){
        System.out.println("instance1 alloc");
    }
    public static Instance1 getInstance(){
        System.out.println("instance1 called");
      
        return instance;
    }
}

静态内部类和饿汉模式都采用类装载的机制保证,当初始化实例的时候只有一个线程执行,保证了多线程下的安全。
JVM会在类初始化的阶段(类装载的阶段)创建一个锁,该锁保证多个线程同步执行类初始化的工作,因此在多线程环境下,类加载的机制依然是安全的。
饿汉模式 是启动就加载,造成资源浪费
静态内部类 只有在调用getInstance方法的时候 才会去装载内部类,从而完成实例的初始化,不造成资源的浪费。 为比较推荐的单例实现方式。

参考

  1. https://blog.csdn.net/y1962475006/article/details/79035250
  2. https://blog.csdn.net/y1962475006/article/details/102642440
  3. 深入理解Javax虚拟机-7.3.5初始化
posted @ 2021-03-19 18:00  zendwang  阅读(38)  评论(0编辑  收藏  举报