线程安全的懒加载单例模式

发布于:2024-07-04 ⋅ 阅读:(19) ⋅ 点赞:(0)

一、什么是单例模式

单例模式是一种设计模式,它确保某个类只有一个实例,并提供一个全局访问点来获取该实例。这种模式在多种编程语言中都有实现,包括JavaC++。单例模式的实现可以采取饿汉式或懒汉式两种方式。饿汉式是在类加载时就创建了实例,而懒汉式则是在首次使用时才创建实例。懒汉式在多线程环境下可能会遇到线程安全问题,需要额外的线程安全措施来保证单例对象的唯一性。

在Java中,单例模式的实现可以通过私有构造函数静态私有对象静态公有函数来实现。

二、编写线程安全的懒加载单例模式

1、单例模式

//单例类:打印机
class Printer{
    //提供静态的私有属性
    private static Printer instance = null;

    //私有的构造方法
    private Printer(){

    }

     //向外部提供创建对象的静态方法
    public static Printer getInstance(){
        return new Printer();
    }
}

2、懒加载

实现懒加载,就是在使用的时候才创建,修改提供对象方法:


     //向外部提供创建对象的静态方法
    public static Printer getInstance(){
        //判断私有的静态对象是否为空
        if(instabce == null){
            //空则创建新对象
            instance = new Printer();
        }
        return instance;
    }

3、线程安全

多线程环境下上述代码存在问题,仍然可能导致对象被多次创建,所以需要加锁,避免多个线程同时创建对象,修改提供对象方法:


     //向外部提供创建对象的静态方法
    public static Printer getInstance(){
        //判断私有的静态对象是否为空
        if(instabce == null){
            //加锁,避免对象被多个线程同时创建
            synchronized(Printer.class){
                //空则创建新对象
                instance = new Printer();
            }
        }
        return instance;
    }

在创建对象的代码块上加上了synchronized阻塞锁,但多个线程同时进入 if 判断里面,对象仍会被多次创建,所以我们需要在加锁的代码块中再次判断,修改代码:


     //向外部提供创建对象的静态方法
    public static Printer getInstance(){
        //判断私有的静态对象是否为空
        if(instabce == null){
            //加锁,避免对象被多个线程同时创建
            synchronized(Printer.class){
                //再次判断
                if(instance != null){
                    return instance;
                }
                //空则创建新对象
                instance = new Printer();
            }
        }
        return instance;
    }

三、单例模式的应用场景

单例模式的应用非常广泛,包括但不限于线程池、缓存、日志、对话框、打印机、显卡的驱动程序对象等。这些应用通常需要管理系统的全局资源,避免出现不一致的状态或浪费资源的情况。

此外,单例模式也有其缺点,例如没有接口导致扩展困难,以及在特定情况下可能会浪费内存资源(如饿汉式实现在类加载时就创建了实例)。因此,在设计单例模式时需要权衡其优缺点,根据具体的应用场景来选择合适的实现方式。