Java基础之单例模式

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例(百度百科)。

单例的实现有以下几种方式:

  • 非延迟加载,也称饿汉模式,顾名思义类加载后就实例化对象。
public class Singleton {

    //私有构造方法
    private Singleton() {}
    //Final 实例
    private static final Singleton instance = new Singleton();  
    //静态无参get方法
    public static Singleton getInstance() {
        return instance;
    }
}
  • 延迟加载,也称懒汉模式,等到用到该实例时再加载。
public class Singleton {

    //私有构造方法
    private Singleton() {}
    //Final 实例
    private static Singleton instance =null;  
    //静态无参get方法
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    
}

synchronized是必须要加的,否则多线程下会出问题:

线程1先进入getInstance方法,然后在new Singleton()执行之前,线程2也进入getInstance方法,因为线程1还没有执行new Singleton()操作,固线程2的if(instance == null)判断也是成立的,因此线程2也new了一个Singleton对象,这样单例模式就失效了,因此需要加同步锁。

  • 双检查模式
public class Singleton {

    //私有构造方法
    private Singleton() {}
    //声明
    private static volatile Singleton instance =null;  
    //静态无参get方法
    public static Singleton getInstance() {
        if(instance == null) {//1
            synchronized (Singleton.class) {
                if(instance == null) {//2
                    instance = new Singleton();//3
                }
            }
        }
        return instance;
    }
    
}

Singleton一定要加volatile修饰,否则同样在多线程下出问题:

线程1先进入getInstance()方法,执行到//3处时,线程2进入getInstance(),此时线程1并未初始化完全instance对象(instance = new Singleton()并非是原子操作,第一步为instance分配内存,此时instance已不再为null,第二步调用其构造方法实例化instance),然而线程2在//1处判断到instance不为空,则直接返回了未初始化完全的instance对象,故而导致系统崩溃。

  • 使用ThreadLocal修复双重检测
public class Singleton {
    
    private static final ThreadLocal<Singleton> threadLocalSingleton = new ThreadLocal<Singleton>();
    private static Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        // 每个线程第一次都会是null
        if (threadLocalSingleton.get() == null) {
            createInstance();
        }
        return singleton;
    }

    private static final void createInstance() {
        synchronized (Singleton.class) {
            if (singleton == null) {
                singleton = new Singleton();
            }
        }
        //标记当前线程已初始化过singleton对象
        threadLocalSingleton.set(singleton);
    }

}
  • 内部类模式

参考: 单例模式与双重检测
更多关于volatile的知识,请看另一篇文章Java基础之volatile

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。