推荐用双重检查锁(DCL)+ volatile 实现线程安全单例:外层判空减少锁竞争,内层加锁保证唯一性,volatile 防止指令重排序;枚举单例可防反射和序列化攻击但不支持延迟加载与继承。
Java里最常写的 Singleton,往往在高并发下出问题。不是加了 synchronized 就万事大吉,也不是靠 static 字段就能一劳永逸。
推荐用双重检查锁(DCL)+ volatile,这是 JDK 6+ 下兼顾性能与安全的写法:
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;
}}
volatile 防止指令重排序,避免其他线程拿到未初始化完成的对象if (instance == null) 判断:外层减少锁竞争,内层保证唯一性if (instance != null) throw new RuntimeException("Singleton already initialized")
readResolve() 方法返回 instance
Spring 的 @Scope("singleton") 是容器级单例——整个 ApplicationContext 中只存在一个 bean 实例,但这个“单例”不等于线

private List cache ),多个线程同时操作它,照样出错request 或 session 作用域的 bean 看起来“每次请求都新建”,其实是 Spring 在每次请求开始时从代理获取新实例,底层仍是工厂管理getBean() 都返回新实例?显式声明 @Scope("prototype"),但注意:prototype bean 的依赖注入仍由容器完成,只是它本身不被缓存手动 new XxxService() 看似简单,但会绕过 Spring 容器的生命周期管理、AOP 代理、依赖注入和事务控制——这在真实项目里几乎不可接受。
ObjectFactory 或 Provider 延迟获取,Spring 4.3+ 支持自动注入@MockBean 或 @SpyBean 替换 prototype bean,比改代码更可控prototype bean 内部若持有 singleton bean 引用,那个 singleton 仍是共享的——多例 ≠ 全隔离Joshua Bloch 在《Effective Java》里力推枚举单例,确实能天然防止反射和序列化攻击,写法极简:
public enum Singleton {
INSTANCE;
public void doSomething() { /* ... */ }}
但它也有现实约束:
INSTANCE
IllegalArgumentException: No enum constant
真要选枚举单例,确保它只做纯粹的状态无关工具类,不涉及外部资源或复杂初始化逻辑。