java单例实例化

时间:2011-01-16 15:35:58

标签: java singleton instance

我找到了三种实例化Singleton的方法,但我怀疑它们中是否有一种是最好的。我在多线程环境中使用它们并且更喜欢懒惰的实例化 样本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),我希望用几句话来理解它。

4 个答案:

答案 0 :(得分:20)

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

public enum ClassName {
    INSTANCE;

    // fields, setters and getters
}

枚举语义保证只有一个INSTANCE

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

答案 1 :(得分:4)

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

样本2和3都是懒惰的。示例2使用具有无同步开销Initialization on demand holder idiom (IODH)。因此它比样本3快。

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

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

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