java单例实例化

我已经找到了三种实例化Singleton的方法,但我怀疑它们中是否有一种是最好的。 我在multithreading环境中使用它们并且更喜欢懒惰的实例化。
样本1:

private static final ClassName INSTANCE = new ClassName(); public static ClassName getInstance() { return INSTANCE; } 

样本2:

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

样本3:

 private static ClassName INSTANCE; public static synchronized ClassName getInstance() { if (INSTANCE == null) INSTANCE = new ClassName(); return INSTANCE; } 

我正在使用ATM的项目到处都使用Sample 2,但我更喜欢Sample 3。 还有Enum版本,但我只是不明白。

这里的问题是 – 在哪些情况下我应该/不应该使用这些变化中的任何一种? 我不是在寻找冗长的解释(关于这一点还有很多其他主题,但它们最终都变成了争论IMO),我希望用几句话来理解它。

在java中实现单例的最安全,最简单的方法是使用枚举(就像你提到的那样):

 public enum ClassName { INSTANCE; // fields, setters and getters } 

枚举语义保证只有一个INSTANCE

如果不使用枚举方法,你必须处理很多方面,比如竞争条件和reflection。 我一直在打破一些框架的单例,并滥用它们,因为它们没有正确编写。 枚举保证没有人会破坏它。

样品1不使用延迟初始化。

样品2和3都是懒惰的。 示例2使用初始化按需持有者惯用法(IODH) ,它没有同步开销 。 因此它比样本3快。

在Effective Java(第3项)中,Joshua Bloch建议单元素枚举类型是实现单例的最佳方法

但是,如果您不确定枚举类型,请坚持使用IODH。

首先,确保您需要一个单例,并且您希望提供对单例的“全局级”访问。 我发现在很多情况下,单身人士的客户不需要知道它是一个单身人士。 相反,他们只需要在实例化时获得服务。

因此,无论您如何获得单例(如果有的话),请考虑更改类访问此对象的方式。 虽然这意味着修改构造函数并更改“分发更改”,但我发现dependency injection框架可以降低成本。 DI框架也可以处理单例实例化(例如,Guice这样做)。

除此之外。 选项3是我熟悉的典型且最常见(和线程安全)版本。 选项1主要用于非延迟初始化(并不总是可接受)。 我从未见过2使用过。

示例1:如果您不需要懒惰的单身人士,请使用。
示例2:永远不要使用 – 太多课程会让人感到困惑。 一个内部类只是为了保存一个变量似乎有点不必要。 样本3:这是一个懒惰的单身人士。 如果需要,请使用它。