本文目录导读:

我为您整理了单例模式的多种经典写法,每种都有其适用场景和优缺点。
饿汉式(静态常量)
public class SingletonEager {
// 类加载时就创建实例
private static final SingletonEager INSTANCE = new SingletonEager();
private SingletonEager() {}
public static SingletonEager getInstance() {
return INSTANCE;
}
}
优点:简单,线程安全
缺点:类加载时就创建实例,可能造成资源浪费
饿汉式(静态代码块)
public class SingletonStaticBlock {
private static SingletonStaticBlock instance;
static {
instance = new SingletonStaticBlock();
}
private SingletonStaticBlock() {}
public static SingletonStaticBlock getInstance() {
return instance;
}
}
适用场景:可以在静态代码块中添加更多初始化逻辑
懒汉式(线程不安全)
public class SingletonLazy {
private static SingletonLazy instance;
private SingletonLazy() {}
public static SingletonLazy getInstance() {
if (instance == null) { // 单线程环境可用
instance = new SingletonLazy();
}
return instance;
}
}
缺点:多线程环境下不安全,不推荐使用
懒汉式(同步方法)
public class SingletonLazySync {
private static SingletonLazySync instance;
private SingletonLazySync() {}
public static synchronized SingletonLazySync getInstance() {
if (instance == null) {
instance = new SingletonLazySync();
}
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关键字
静态内部类(推荐)
public class SingletonHolder {
private SingletonHolder() {}
// 静态内部类,调用getInstance时才会加载
private static class SingletonInstance {
private static final SingletonHolder INSTANCE = new SingletonHolder();
}
public static SingletonHolder getInstance() {
return SingletonInstance.INSTANCE;
}
}
优点:
- 线程安全(类加载机制保证)
- 懒加载(使用时才加载内部类)
- 性能好
枚举方式(最佳实践)
public enum SingletonEnum {
INSTANCE; // 枚举元素本身就是单例
private String name = "singleton";
public void showMessage() {
System.out.println("枚举单例: " + name);
}
// 使用方式
public static void main(String[] args) {
SingletonEnum.INSTANCE.showMessage();
}
}
优点:
- 最简单
- 线程安全
- 防反射攻击
- 防序列化破坏
完整对比代码(含测试)
public class SingletonDemo {
public static void main(String[] args) {
// 测试各种单例
testSingleton("饿汉式", SingletonEager::getInstance);
testSingleton("静态代码块", SingletonStaticBlock::getInstance);
testSingleton("懒汉式", SingletonLazySync::getInstance);
testSingleton("双重检查锁", SingletonDCL::getInstance);
testSingleton("静态内部类", SingletonHolder::getInstance);
testSingleton("枚举", () -> SingletonEnum.INSTANCE);
// 多线程测试
testThreadSafety();
}
private static void testSingleton(String name, Supplier<Object> supplier) {
Object s1 = supplier.get();
Object s2 = supplier.get();
System.out.println(name + " 是否为单例: " + (s1 == s2));
}
private static void testThreadSafety() {
// 测试DCL是否线程安全
ExecutorService pool = Executors.newFixedThreadPool(10);
Set<SingletonDCL> set = ConcurrentHashMap.newKeySet();
for (int i = 0; i < 100; i++) {
pool.execute(() -> set.add(SingletonDCL.getInstance()));
}
pool.shutdown();
System.out.println("DCL线程安全测试 实例数量: " + set.size());
}
}
选型建议
-
最优选:枚举方式(
SingletonEnum)最简洁,天然线程安全,防止反射和序列化破坏
-
项目中常用:静态内部类(
SingletonHolder)实现简单,性能好,懒加载
-
注重性能:双重检查锁(
SingletonDCL)性能好,但注意volatile使用
-
简单场景:饿汉式(
SingletonEager)类不复杂,无资源浪费时使用
-
避免使用:纯懒汉式(非线程安全)
完整演示代码(可直接运行)
import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Supplier; // 在这里加入上面所有的单例类... // 然后运行 SingletonDemo 测试
这8种写法覆盖了Java单例模式的所有经典实现,您可以根据实际项目需求选择最合适的方式,在实际开发中,枚举和静态内部类是最高效、最安全的推荐方案。