单例模式之常见模式详解

单例模式的定义

单例模式是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例。

在单例模式中,类的构造函数被私有化,这样其他类就无法直接创建该类的实例。而是通过一个静态方法或者属性来获取类的唯一实例。

单例模式的分类

在Java中实现单例模式的方法有很多,这里介绍最常见的两种

饿汉模式

以下是具体实现:


public class Singleton {
    
    
    //此处,先把实例创建出来
    private static  Singleton instance=new Singleton();

    //如果需要使用这个唯一实例,统一通过 Singleton.getInstance()方法来获取。
    public static Singleton getInstance(){
    
    
        return  instance;
    }

    //为了避免Singleton 类不小心被复制出多份来
    //把构造方法设置为private.在类外面,就无法通过new的方式来创建这个Singleton实例
    private Singleton(){
    
    

    }
}

在这里插入图片描述

此处static起着至关重要的作用:

  • static 保证这个实例唯一
  • static 保证这个实例确实在一定时机中被创建出来
    static 修饰使得当前 instance 属性是类属性,类属性是在类对象上的,类对象在一个java进程里是唯一的(只是在类加载阶段被创建出一个实例)

补充知识点
类加载:
java代码中的每个类都会在编译完成后得到 .class 文件。JVM运行时会加载这个 .class文件,读取其中的二进制指令,并且在内存中构造出对应的类对象。(形如Singleton.class)

在这里插入图片描述

  • 把构造方法设为private,在类外面,就无法通过new的方式来创建这个实例了。

饿汉模式的优点是实现简单、线程安全,因为实例在类加载时就已经创建好了。但缺点是如果该实例在整个程序运行期间没有被使用到,会造成资源浪费。

懒汉模式

以下是具体实现:

public class SingletonLazy {
    
    

    private static  SingletonLazy instance=null;

    public static SingletonLazy getInstance(){
    
    
        if(instance==null){
    
    
            instance=new SingletonLazy();
        }
        return instance;
    }

    private SingletonLazy(){
    
    

    }

}

在这里插入图片描述

懒汉模式没有在类加载时进行初始化,而是在第一次使用该类的实例时,通过判断实例是否已经存在来决定是否创建实例。(延迟实例化,在需要时才创建唯一的实例。)

懒汉模式优点是实现简单,只有在需要时才创建实例,避免了资源浪费。但缺点是在多线程环境下可能会出现线程安全问题,需要额外处理。

如何让上述懒汉模式能够线程安全呢?进行加锁操作
在这里插入图片描述

由于使用了synchronized关键字,可能会影响性能。为了提高性能,可以使用双重检查锁定等方式进行优化。

上述代码会导致每次 getInstance() 操作都要加锁,加锁操作是有开销的,然而如果判断instance 的值是非空时,就会直接触发return操作,此时由于没有修改操作,就没必要加锁。

如下:
在这里插入图片描述

为了避免上述代码可能会遇到的内存可见性问题和指令重排序问题,使用volatile关键字进行优化。
代码如下:

public class SingletonLazy {
    
    
    private volatile static  SingletonLazy instance=null;

    public static SingletonLazy getInstance(){
    
    

        if (instance == null) {
    
    
            synchronized (SingletonLazy.class) {
    
    
                if (instance == null) {
    
    
                    instance = new SingletonLazy();
                }
            }
        }

        return instance;
    }

    private SingletonLazy(){
    
    
    }

}

单例模式的主要特点

  • 私有的构造函数:通过将构造函数设为私有,防止其他类直接创建实例。
  • 静态的实例变量:在类内部定义一个静态的实例变量,用于保存类的唯一实例。
  • 静态的获取方法:提供一个静态的方法或属性,用于获取类的唯一实例。这个方法会在第一次调用时创建实例,并在后续调用时返回同一个实例。

单例模式的应用场景

  • 系统中某个类的对象只需要存在一个实例,例如配置信息类、日志记录类等。
  • 需要频繁创建和销毁对象的场景,通过使用单例模式可以节省系统资源。
  • 对象需要被共享或者全局访问的场景,例如线程池、数据库连接池等。

总结

在实现单例模式时,需要注意线程安全性和延迟加载的问题。可以使用加锁、双重检查锁定等方式来确保线程安全,并且在需要时才创建实例,避免资源浪费。

猜你喜欢

转载自blog.csdn.net/m0_63904107/article/details/131731589