一、以下是Java中创建单例模式的几种常见方法,每种方法都有其特点和适用场景
1. 使用枚举实现线程安全的单例模式
Joshua Bloch推荐的线程安全实现方式,还能防止反序列化破坏单例
public enum SingletonEnum {
INSTANCE;
private final DatabaseService databaseService;
private SingletonEnum() {
this.databaseService = new DatabaseService();
}
public DatabaseService getDatabaseService() {
return databaseService;
}
}
class DatabaseService {
public void executeQuery(String query) {
System.out.println("Executing query: " + query);
}
}
class MainTest {
public static void main(String[] args) {
DatabaseService service1 = SingletonEnum.INSTANCE.getDatabaseService();
DatabaseService service2 = SingletonEnum.INSTANCE.getDatabaseService();
service1.executeQuery("SELECT * FROM users");
System.out.println("Is same instance: " + (service1 == service2));
}
}
2. 饿汉式单例
类加载时就初始化实例,线程安全但可能造成资源浪费
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
3. 懒汉式单例(线程不安全)
延迟加载但多线程环境下可能创建多个实例
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
4. 线程安全的懒汉式
通过synchronized保证线程安全,但性能较低
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
5. 双重校验锁(DCL)
线程安全且性能较好,需配合volatile使用
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;
}
}
6. 静态内部类实现
线程安全且实现懒加载,推荐方式之一
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
7. 容器式单例(饿汉式单例的变种)
适用于管理多个单例对象,如Spring容器实现
public class SingletonManager {
private static Map<String, Object> instances = new ConcurrentHashMap<>();
public static void register(String key, Object instance) {
if (!instances.containsKey(key)) {
instances.put(key, instance);
}
}
public static Object getInstance(String key) {
return instances.get(key);
}
}
二、 优势对比
以下是枚举单例与其他单例实现方式的对比分析,从线程安全、反序列化防护、反射防护、实现复杂度等维度综合评估:
★ 关键结论:
- 枚举单例在安全性上全面领先
- 静态内部类是延迟加载的最佳备选
- 避免使用非线程安全的懒汉式
枚举实现单例是《Effective Java》推荐的最佳实践,适合需要高安全性和简洁性的场景。