单例模式:饿汉式和懒汉式的实现

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

一:饿汉式

1、直接创建适合简单的单例模式:

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

 2、适合需要较复杂的初始化的单例模式:

public class SingleTon{
   private final static SingleTon INSTANCE ;
    private String info;
    static {
        //初始化参数
    }
    private SingleTon(String info){
        this.info = info;
    }
   public static SingleTon getInstance(){ return INSTANCE; }}        

二:懒汉式

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

此方法线程不安全

1、双锁检验懒汉式

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重排解决。

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

2、静态内部类

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

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

3、枚举

public enum Singleton{
INSTANCE;
}

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

原文地址:https://www.cnblogs.com/Noctis/p/10519137.html