单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点到该实例。单例模式在很多场景下非常有用,特别是当某个类在整个应用程序中管理全局状态时,如配置管理器、连接池管理等。
请重点关注懒汉式和饿汉式
实现单例模式的关键点:
- 私有构造函数:防止外部直接使用
new
关键字创建类的实例。 - 私有静态实例:类的内部维护一个私有静态实例。
- 公共静态方法:提供一个公共的静态方法供外部访问,用于获取类的唯一实例。如果实例不存在,此方法将创建实例;如果已存在,直接返回该实例。
实现方式
1. 懒汉式(线程不安全)
懒汉式单例在首次使用时实例化自己,简单但线程不安全。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2. 懒汉式(线程安全)
通过加锁synchronized
保证线程安全,但每次访问都要加锁,影响性能。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3. 饿汉式
饿汉式在类加载时就创建实例,保证线程安全,但可能造成资源浪费。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
4. 双重校验锁(Double-Checked Locking)
双重校验锁既保证了懒加载,又保证了线程安全,且只在第一次创建实例时同步。
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
5. 静态内部类
使用静态内部类,利用JVM本身机制保证线程安全。这种方式既实现了懒加载,又保证了线程安全。
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
6. 枚举实现
使用枚举方式,这是实现单例模式的最佳方法,不仅能避免多线程同步问题,还能防止反序列化重新创建新的对象。
public enum Singleton {
INSTANCE;
public void someMethod() {
// 方法实现
}
}
使用场景与优点
- 资源共享:适用于访问共享资源的情况,如配置信息、硬件接口等。
- 控制资源的使用:通过单例模式控制资源的创建,避免对资源的过度请求。
- 全局访问点:提供了一个全局访问点,全局只有一个实例。
注意事项
虽然单例模式很有用,但也要注意其带来的问题,如隐藏了类之间的依赖关系,可能导致代码难以测试;在分布式系统中,需要额外的机制来确保全局唯一性等。