1. 设计模式详解
单例模式是一种创建对象的设计模式,它确保一个类只有一个实例,并提供全局访问点以获取该实例。
在单例模式中,类负责创建自己的唯一实例,并确保任何其他对象只能访问该实例。这对于需要共享状态或资源的情况非常有用,例如数据库连接,日志记录器或线程池。
单例模式的主要特点包括:
-
私有构造函数:单例类的构造函数被声明为私有,这样其他类无法直接实例化该类。
-
静态实例变量:单例类内部维护一个静态实例变量,用于保持对单例实例的引用。
-
静态获取方法:单例类提供一个静态方法,以便其他类可以通过该方法获取单例实例。通常,该方法在首次调用时会创建单例实例,并在后续调用时返回该实例。
2.单例模式代码
单例模式实现代码很简单:
/**
* @Author: stukk
* @Description: 单例模式
* @DateTime: 2023-12-17 22:14
**/
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance() {
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
public void showMessage(){
System.out.println("我是单例模式");
}
}
/**
* @Author: stukk
* @Description: 客户端
* @DateTime: 2023-12-17 22:16
**/
public class SingletonMode {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
singleton.showMessage();
}
}
3. 单例模式的多种实现方式
单例模式有多种形式,每种形式都在实现单例模式的基本原则上略有不同。
3.1. 懒汉式单例模式(Lazy Initialization):
也就是上面展示的代码
特点:在首次调用获取实例的方法时才创建单例实例
优点:延迟实例化,节省资源
缺点:需要考虑线程安全
线程安全版本:
public class LazySingleton {
private static LazySingleton singleton;
private LazySingleton(){}
public static synchronized LazySingleton getInstance() {
if(singleton == null){
singleton = new LazySingleton();
}
return singleton;
}
3.2. 饿汉式单例模式(Eager Initialization):
特点:在类加载的时候就创建单例实例
优点:简单直接、线程安全
缺点:加载的时候就实例化,可能会实例到不需要使用的类,浪费资源
代码:
/**
* @Author: stukk
* @Description: 饿汉式单例模式
* @DateTime: 2023-12-17 22:31
**/
public class EagerSingleton {
private EagerSingleton(){}
private static EagerSingleton singleton = new EagerSingleton();
public static EagerSingleton getInstance(){
return singleton;
}
public void showMessage(){
System.out.println("我是饿汉单例模式");
}
}
3.3.双重检查锁单例模式(DCL——Double-Checked-Locking)
特点:结合了懒汉式与同步锁机制,在首次调用获取实例的方法式进行双重检查,提高性能。
优点:延迟实例化且线程安全,性能相对较高
缺点:在某些情况下可能还是会出错,比如多线程环境下的指令重排序,会导致不正确的结果。
示例代码:
/**
* @Author: stukk
* @Description: 双重检查锁单例模式
* @DateTime: 2023-12-17 22:41
**/
public class DCLSingleton {
private DCLSingleton(){}
private volatile static DCLSingleton dclSingleton;
public static DCLSingleton getInstance(){
if(dclSingleton == null){
synchronized (DCLSingleton.class){
if(dclSingleton == null){
dclSingleton = new DCLSingleton();
}
}
}
return dclSingleton;
}
public void showMessage(){
System.out.println("我是双重校验锁单例模式");
}
}
3.4. 枚举单例模式(Enum)
特点:使用枚举类实现单例,枚举类保证只有一个实例。
优点:简单、线程安全、防止反射和序列化攻击。
示例代码:(这里以计数器为例子)
/**
* @Author: stukk
* @Description: 使用枚举实现
* @DateTime: 2023-12-17 22:46
**/
public enum EnumSingleton {
INSTANCE;
// 假设是个计数器
private int counter;
// 私有构造函数
private EnumSingleton(){
counter = 0;
}
// 获取计数器的值
public int getCounter(){
return counter;
}
// 计数器++
public void addCounter(){
counter ++;
}
// 其他 操作
public void showMessage(){
System.out.println("我是枚举单例模式,此时计数器值为:"+getCounter());
}
}
/**
* @Author: stukk
* @Description: 客户端
* @DateTime: 2023-12-17 22:16
**/
public class SingletonMode {
public static void main(String[] args) {
EnumSingleton singleton = EnumSingleton.INSTANCE;
singleton.showMessage();
singleton.addCounter();
singleton.showMessage();
}
}
枚举单例模式的使用非常简单,只需要使用枚举类的名称后跟 .INSTANCE
即可获取到单例实例,无需担心线程安全性或其他实现细节。