Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么静态单例是避免';DCL';?_Java_Singleton_Dcl - Fatal编程技术网

Java 为什么静态单例是避免';DCL';?

Java 为什么静态单例是避免';DCL';?,java,singleton,dcl,Java,Singleton,Dcl,当需要单例时,静态字段是一个优雅的解决方案吗 class HelperSingleton { static Helper singleton = new Helper(); public static Helper getInstance() { return singleton; } } 当两个线程同时访问getInstance时,字段singleton是否有可能未完全初始化?或者查看帮助对象字段的默认值,而不是构造函数中设置的值? 静态单例也是惰性初始

当需要单例时,静态字段是一个优雅的解决方案吗

class HelperSingleton {
  static Helper singleton = new Helper();

  public static Helper getInstance() {
       return singleton;
     }
  }
当两个线程同时访问
getInstance
时,字段
singleton
是否有可能未完全初始化?或者查看帮助对象字段的默认值,而不是构造函数中设置的值? 静态单例也是惰性初始化吗

我是说,
static Helper singleton=new Helper()
这是原子弹吗?并且不会返回默认值?

请查看


有许多样式可以解释好的/坏的。

我认为最优雅的单身解决方案是:

public enum Singleton {

    INSTANCE;

    public Singleton getInstance() {
        return INSTANCE;
    }
}
使用单例模式有些问题,因为有时您不知道您实际上只有一个。例如在使用类加载器时考虑该情况。

顺便说一句,问题(和其他问题)有一个彻底的解释。

如果是这样的话:

class HelperSingleton {
  static Helper singleton = null;
  public static Helper getInstance() {
      if(singleton == null) {
         singleton = new Helper();
      }
      return singleton;
    }
}
这里可能有一种可能性:

  • 线程1调用
    getInstance()
    方法并确定
    singleton
    null

  • 线程1进入if块,但在创建新实例之前被线程2抢占

  • 线程2调用
    getInstance()
    方法并确定实例为
    null

  • 线程2进入if块并创建一个新的
    Helper
    对象,并将变量
    singleton
    分配给这个新对象

  • 线程2返回单例对象引用

  • 线程2被线程1抢占

  • 线程1从它停止的地方开始执行
    singleton=newhelper()将导致创建另一个单例对象

  • 线程1返回这个对象

  • 因此,我们以两个实例结束。创建单例的最佳方法是使用enum

    在这里,当类被加载时,
    Helper
    的一个新实例被创建,并且
    singleton
    保存对该实例的引用。您可以在中获得详细的初始化过程。

    1)当线程访问静态getInstance时,类加载器第一次必须加载HelperSingleton类,它将在加载类之前锁定其他线程。因此存在隐式同步。J.Bloch“有效Java”第71项现代虚拟机将仅同步字段访问以初始化类。初始化类后,VM将修补代码,以便后续对字段的访问不涉及任何测试或同步

    2) 您的singleon是懒惰的,因为只有一个访问点—getInstance。不仅实例是按需创建的,整个类也是按需加载的。类将不会被初始化
    在使用之前[JLS,12.4.1]。

    getInstance()不应该是静态的吗?应该有一个私有构造函数。而
    singleton
    应该是私有的和最终的。理想情况下,类也应该是
    final
    。[编辑]dangit@JonSkeet,你偷了我的答案,你比我快:-关于单例类和线程安全,这个问题可能是一个有用的读物。谢谢,但我想知道的是静态帮助程序单例=新帮助程序();始终向客户端返回一个完全初始化的引用?是否有任何关于您提到的第1点的官方文档?我认为J.Bloch的有效Java是可以信任的,因为作者领导了许多Java平台功能的设计和实现。呃,上面的静态字段singleton和lazy initaialization holder类之间有什么区别吗?如果类中有其他静态方法,则需要将实例包装在holder中以保持其惰性。另外,lazy是一种昂贵的实例化方法。。。
    static Helper singleton = new Helper();