关于java:Singleton Pattern的最佳解决方案是什么?

What is the best solution for Singleton Pattern?

本问题已经有最佳答案,请猛点这里访问。

如果使用实例持有者类实现单例模式,编译器将生成另一个名为classname$1.class的类文件。您可以通过以下链接找到问题:这里.所以我的问题是,单例模式的解决方案是什么?重复检查?


您似乎在问这个singleton代码是如何实现线程安全初始化的:

1
2
3
4
5
6
7
8
9
10
11
public final class Test {
     static final class TestHolder {
         private static final Test INSTANCE = new Test();
     }    

     private Test() {}

     public static Test getInstance() {
         return TestHolder.INSTANCE;
     }
}

解决方案的线程安全性得到保证,因为:

  • 静态初始化是以线程安全的方式执行的,并且
  • 初始化后,无需进一步同步即可使用final变量。

它没有进行双重检查锁定。

注意,这个特殊的模式是线程安全的,并且是惰性初始化的。如果您希望使用非延迟初始化的线程安全单例,那么:

1
2
3
4
5
6
7
8
9
public final class Test {
     private static final Test INSTANCE = new Test();

     private Test() {}

     public static Test getInstance() {
         return INSTANCE;
     }
}

也可以采用"单体"方法。不管多莉工程师怎么说。

使用双检查锁定的懒惰初始化可以从Java 5向前正确地执行(如果使用EDCOX1 OR 5表示正确),但是在Java 1.4 .x和更早的时候,习惯用语被打破。


您可以使用简单的枚举。

1
2
3
public enum Singleton {
    INSTANCE;
}

您可以简单地将INSTANCE作为Singleton.INSTANCE访问,而不是调用getInstance()方法。默认情况下,创建枚举实例是线程安全的。


根据部署架构,在Java中实现单体变得非常困难。当你谈论单身时,你也必须谈论他们的范围/背景。因为很少有人理解这种单子常被称为邪恶,被认为是反模式。

如果要部署到应用服务器外部的单个JVM,则惯用方法是在其内部实现类的私有最终静态实例,并通过适当命名的方法(getInstance()是常见的)公开该实例,并使类的构造函数成为私有的。这是一个单实例,约束为一个类加载器和一个JVM。

然而,这种情况非常罕见。

在所有其他情况下,您必须考虑类加载器问题以及将代码部署到多个JVM/服务器的问题。在典型的JavaEE应用程序容器中,通常使用自己的类加载器加载每个战争。如果每一场战争都依赖于一个包含单重子的罐子,那么他们每个人都会得到自己的单重子副本。如果singleton是用于,比如说,一个DB连接,并且允许您使用很多数据库连接,那么这就可以了。但是,如果单例程序应该保护对有限资源的访问,那么这不会很好地工作,因为每个webapp都有一个类能够访问该资源。这里的singleton的作用域是容器作用域。

在完整的企业部署中,随着集群和实时故障转移,情况变得更糟。在这种环境中,您有许多同时运行的软件副本。很难想象一个Java独生子在这个范围内工作——企业范围。在这个层次上,您需要弄清楚单例创建或执行的单一真相来源是什么(如果可以有多个实例,但一次只能有一个实例处理请求),并且您创建的同一类型的所有单例都必须遵从单一真相来源——企业信号量。


我会在JDK1.5之后使用Enum。有关详细信息,请查看htis链接:http://javarevisited.blogspot.in/2012/07/why-enum-singleton-are-better-in-java.html

  • 不建议双重检查锁定,它不能提供性能。
  • 您提到的链接中的解决方案是一个使用静态内部类的有效解决方案,因为它不使用同步并使用延迟加载,但枚举与性能一起最容易实现。
  • 下面的文章解释了为什么双检查锁定可能是一个坏的选择[正如托马斯指出的那样,BEOW文章中提到的双重检查锁定问题是用Java 1.5固定的:]:HTTP://www. iBM/CuxeWorks/Java/Labaly/J-DCL/NETX.HTML