单例模式:双锁检验学习

时间:2019-03-12
本文章向大家介绍单例模式:双锁检验学习,主要包括单例模式:双锁检验学习使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

先列举最常见的单例模式:

1:懒汉式

Class Singleton{
    private static Singleton instance = null;
    
    private Singleton(){}
    
    public static Singleton getInstance(){
        if(instance == null){
             instance = new Singleton();
        }
        return instance;
    }
}    

此方法线程不安全

2:饿汉式

public class SingleTon{
   private static SingleTon INSTANCE = new SingleTon();
   private SingleTon(){}
   public static SingleTon getInstance(){ return INSTANCE; }}

加载类时就初始化对象,占用内存

3:双锁检验懒汉式

class Singleton{
    private static Singleton instance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance==null){
                    instance = new Singleton();
                }
            }        
        }
        return instance;
    }    
}

此方法看似解决了线程安全问题,实际上还存在隐患,可能出现线程a还在初始化instance但未完全初始化时,线程b就通过instance!=null判断返回了这个instance对象。

这是由于JVM的重排序,导致instance已经指向了一块内存,但这块内存并没有初始化。其根本原因是对象实例化不是原子操作,其顺序可能被重排,可分为三步:

  • 1.分配一块内存空间
  • 2.在这块内存上初始化一个DoubleCheckLock的实例
  • 3.将声明的引用instance指向这块内存

具体原因可参考:https://blog.csdn.net/zy13608089849/article/details/82703192

这里可以给instance加上volatile修饰符禁止jvm重排解决。

其他线程安全的方法还有:

4:静态内部类

public class SingleTon{
  private SingleTon(){}
 
  private static class SingleTonHoler{
     private static SingleTon INSTANCE = new SingleTon();
 }
 
  public static SingleTon getInstance(){
    return SingleTonHoler.INSTANCE;
  }
}

由于内部类只会在getInstance()时才会被加载,且只加载一次,因此也可以看作是线程安全的懒汉式

5:枚举

public enum Singleton{
INSTANCE;
}

大概是最简单的单例了哈哈