Singleton中的线程安全性

我知道Java中的双重锁定已被破坏,那么在Java中使单例线程安全的最佳方法是什么? 我想到的第一件事是:

class Singleton{ private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance == null) instance = new Singleton(); return instance; } } 

这有用吗? 如果是这样,它是最好的方式(我想这取决于具体情况,所以说明特定技术最好的时候会有用)

Josh Bloch建议使用单元素enum类型来实现单例(请参阅Effective Java 2nd Edition,第3项:使用私有构造函数或枚举类型强制执行单例属性 )。

有些人认为这是一个黑客,因为它没有明确表达意图,但它确实有效。

以下示例直接来自本书。

 public enum Elvis { INSTANCE; public void leaveTheBuilding() { ... } } 

以下是他的结论:

这种方法更简洁,免费提供序列化机制,并提供针对多个实例的铁定保证,即使面对复杂的序列化或reflection攻击。 虽然这种方法尚未被广泛采用, 但单元素枚举类型是实现单例的最佳方法


关于enum常数单身保证

JLS 8.9。 枚举

枚举类型没有除其枚举常量定义的实例之外的实例。 尝试显式实例化枚举类型(第15.9.1节)是编译时错误。

Enumfinal clone方法确保永远不会克隆枚举常量,并且序列化机制的特殊处理可确保不会因反序列化而创建重复实例。 禁止对枚举类型进行reflection实例化。 总之,这四件事确保除了枚举常量定义的实例之外不存在枚举类型的实例。


在延迟初始化

以下片段:

 public class LazyElvis { enum Elvis { THE_ONE; Elvis() { System.out.println("I'M STILL ALIVE!!!"); } } public static void main(String[] args) { System.out.println("La-dee-daaa..."); System.out.println(Elvis.THE_ONE); } } 

产生以下输出:

 La-dee-daaa... I'M STILL ALIVE!!! THE_ONE 

如您所见, THE_ONE常量在第一次访问之前不会通过构造函数实例化。

我发现你的实现没有问题(除了由于其他原因而其他方法可能会使用单例监视器的锁定这一事实,因此,不必要地阻止其他一些线程获取实例)。 这可以通过引入额外的Object lock来锁定来避免。

这篇维基百科文章提出另一种方法:

 public class Something { private Something() { } private static class LazyHolder { private static final Something INSTANCE = new Something(); } public static Something getInstance() { return LazyHolder.INSTANCE; } } 

来自文章:

此实现是一个性能良好且并发的实现,在所有Java版本中都有效。

该实现依赖于Java虚拟机(JVM)中明确指定的初始化执行阶段; 有关详细信息,请参阅Java语言规范(JLS)的第12.4节。

我的偏好是这样做:

 class Singleton { private static final INSTANCE = new Singleton(); private Singleton(){} public Singleton instance(){ return INSTANCE; } } 

您很少需要延迟初始化。 您应该始终以热切的初始化开始,如果发现问题,只能更改为延迟初始化。 除非你已经测量并确定Singleton实例化是性能问题的罪魁祸首,否则只需使用急切的初始化。 它更简单,更高效。

您可以肯定使用枚举,但我个人并不打扰,因为普通急切实例化的好处是安全性(针对reflection攻击),并且大多数时候我的代码很容易受到此类攻击:p

Josh Bloch推荐2种解决方案:

1)恶化:

 class Singleton { public static Singleton instance = new Singleton(); ... } 

2)更好:

 public enum Singleton { INSTANCE; ... } 

您可以使用wiki的这段代码

 public class Singleton { // Private constructor prevents instantiation from other classes private Singleton() {} /** * SingletonHolder is loaded on the first execution of Singleton.getInstance() * or the first access to SingletonHolder.INSTANCE, not before. */ private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }