本文目录导读:

- 饿汉式(线程安全,加载时就创建)
- 懒汉式(线程不安全)
- 懒汉式(线程安全,同步方法)
- 双重检查锁定(DCL,推荐方式)
- 静态内部类(推荐方式)
- 枚举方式(最安全,Effective Java推荐)
- 完整示例:数据库连接池管理器
- 测试代码
- 总结:如何选择?
我来为你详细介绍Java中实现单例模式的几种常见方法,从基础到高级逐步说明。
饿汉式(线程安全,加载时就创建)
public class SingletonEager {
// 类加载时就创建实例
private static final SingletonEager instance = new SingletonEager();
// 私有构造方法
private SingletonEager() {}
// 提供全局访问点
public static SingletonEager getInstance() {
return instance;
}
}
优点:实现简单,线程安全(类加载机制保证) 缺点:类加载时就创建,可能造成资源浪费
懒汉式(线程不安全)
public class SingletonLazyUnsafe {
private static SingletonLazyUnsafe instance;
private SingletonLazyUnsafe() {}
public static SingletonLazyUnsafe getInstance() {
if (instance == null) {
instance = new SingletonLazyUnsafe();
}
return instance;
}
}
问题:多线程环境下可能创建多个实例
懒汉式(线程安全,同步方法)
public class SingletonLazySafe {
private static SingletonLazySafe instance;
private SingletonLazySafe() {}
// 使用synchronized保证线程安全
public static synchronized SingletonLazySafe getInstance() {
if (instance == null) {
instance = new SingletonLazySafe();
}
return instance;
}
}
缺点:每次调用都加锁,性能较差
双重检查锁定(DCL,推荐方式)
public class SingletonDCL {
// volatile关键字防止指令重排序
private static volatile SingletonDCL instance;
private SingletonDCL() {}
public static SingletonDCL getInstance() {
if (instance == null) {
synchronized (SingletonDCL.class) {
if (instance == null) {
instance = new SingletonDCL();
}
}
}
return instance;
}
}
关键点:
volatile:防止instance = new SingletonDCL()的指令重排序- 双重检查:减少锁的开销
- 实际开发中最推荐的方式之一
静态内部类(推荐方式)
public class SingletonStaticInner {
private SingletonStaticInner() {}
// 静态内部类
private static class SingletonHolder {
private static final SingletonStaticInner INSTANCE = new SingletonStaticInner();
}
public static SingletonStaticInner getInstance() {
return SingletonHolder.INSTANCE;
}
}
优点:
- 延迟加载(只有在getInstance调用时才加载内部类)
- 线程安全(类加载机制保证)
- 性能好
枚举方式(最安全,Effective Java推荐)
public enum SingletonEnum {
INSTANCE;
// 可以添加其他方法
public void doSomething() {
System.out.println("Singleton do something");
}
}
优点:
- 简单、安全
- 自动支持序列化
- 防止反射攻击
- 绝对防止多次实例化
完整示例:数据库连接池管理器
public class DatabaseConnectionPool {
// 使用双重检查锁定
private static volatile DatabaseConnectionPool instance;
private List<Connection> connections = new ArrayList<>();
private final int MAX_CONNECTIONS = 10;
private DatabaseConnectionPool() {
initializePool();
}
private void initializePool() {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
// 模拟创建数据库连接
connections.add(createConnection());
}
}
private Connection createConnection() {
// 实际项目中连接数据库
System.out.println("创建数据库连接");
return null; // 简化示例
}
public static DatabaseConnectionPool getInstance() {
if (instance == null) {
synchronized (DatabaseConnectionPool.class) {
if (instance == null) {
instance = new DatabaseConnectionPool();
}
}
}
return instance;
}
public Connection getConnection() {
if (connections.isEmpty()) {
return null;
}
return connections.remove(0);
}
public void releaseConnection(Connection conn) {
connections.add(conn);
}
}
测试代码
public class SingletonTest {
public static void main(String[] args) {
// 测试各种单例模式
testBasicSingletons();
testEnumSingleton();
testMultiThreadSafety();
}
private static void testBasicSingletons() {
SingletonDCL s1 = SingletonDCL.getInstance();
SingletonDCL s2 = SingletonDCL.getInstance();
System.out.println("DCL模式: " + (s1 == s2)); // true
SingletonStaticInner s3 = SingletonStaticInner.getInstance();
SingletonStaticInner s4 = SingletonStaticInner.getInstance();
System.out.println("静态内部类: " + (s3 == s4)); // true
SingletonEnum s5 = SingletonEnum.INSTANCE;
SingletonEnum s6 = SingletonEnum.INSTANCE;
System.out.println("枚举模式: " + (s5 == s6)); // true
}
private static void testEnumSingleton() {
SingletonEnum.INSTANCE.doSomething();
}
private static void testMultiThreadSafety() {
// 多线程测试
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executor.execute(() -> {
SingletonDCL instance = SingletonDCL.getInstance();
System.out.println(Thread.currentThread().getName() + ": " + instance.hashCode());
});
}
executor.shutdown();
}
}
如何选择?
| 场景 | 推荐方式 | 理由 |
|---|---|---|
| 通用场景 | 静态内部类 | 延迟加载、线程安全、性能好 |
| 高性能要求 | 双重检查锁定(DCL) | 延迟加载、最小化同步开销 |
| 最安全 | 枚举 | 防反射、防序列化破坏 |
| 简单场景 | 饿汉式 | 实现最简单 |
建议:
- 一般项目:使用静态内部类方式
- 高性能要求:使用DCL方式
- 涉及序列化:使用枚举方式
- 避免使用:懒汉式(同步方法)和线程不安全的懒汉式
这样的实现既保证了单例的唯一性,又兼顾了性能和安全性。