【多线程】单例模式与多线程

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式具有典型的三个特点:

  • 只有一个实例。
  • 自我实例化。
  • 提供全局访问点。

1、饿汉模式

在类加载的时候就创建实例,饿汉模式是线程安全
但是如果不使用,也产生了不需要的实例

public class Singleton {
    //1、持有自己类型的属性
    private static Singleton instance=new Singleton();
    //2、私有的构造器
    private Singleton() {
    }
    //3、提供对外获取实例的方法
    public static Singleton getInstance(){
        return instance;
    }
}

2、懒汉模式

懒汉模式:在调用getInstance方法时,实例才被创建

2.1、存在多线程下会产生多个实例!!!!!!,这与单例模式的初衷相悖

public class Singleton {
    //1、持有自己类型的属性
    private static Singleton instance;
    //2、私有的构造器
    private Singleton() {
    }
    //3、提供对外获取实例的方法
    public static Singleton getInstance(){
        if(instance == null){
            instance=new Singleton();
        }
        return instance;
    }
}

2.2、改进一、对 getInstance()方法加synchronized关键字修饰

优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

public class Singleton {
    //1、持有自己类型的属性
    private static Singleton instance;
    //2、私有的构造器
    private Singleton() {
    }
    //3、提供对外获取实例的方法
    synchronized public static Singleton getInstance(){
        if(instance == null){
            instance=new Singleton();
        }
        return instance;
    }
}

2.3、改进二、double-checked locking、双检锁、DCL

大多数多线程结合单例模式的解决方案
但是还是存在小概率的线程安全问题,是因为有指令重排序的存在。解决办法volatile关键字修饰属性。

public class Singleton {
    //1、持有自己类型的属性
    private static Singleton instance;
    //2、私有的构造器
    private Singleton() {
    }
    //3、提供对外获取实例的方法
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) { // 在synchronized 前后进行判断
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

2.4、改进三、使用静态内部类

是否 Lazy 初始化:是
是否多线程安全:是

public class Singleton {
    //静态内部类
    private static class SingletonHolder {
        private static  Singleton INSTANCE = new Singleton();
    }
    //私有的构造器
    private Singleton (){
    }
    //提供对外获取实例的方法
    public static  Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

3、使用枚举

是否 Lazy 初始化:否
是否多线程安全:是

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

总结

饿汉模式是线程安全的,但是类加载时就初始化,浪费内存。
懒汉模式可以使用DCL双检索方式、静态内部类。
如果涉及到反序列化创建对象时,可以使用枚举。

参考:
https://www.runoob.com/design-pattern/singleton-pattern.html

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

推荐阅读更多精彩内容