java - Java 有静态顺序初始化失败吗?

标签 java singleton static-order-fiasco

这里最近的一个问题有以下代码(好吧,类似于此)来实现没有同步的单例。

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

现在,我想明白这是在做什么。由于实例是 static final,它是在任何线程调用 getInstance() 之前很久就构建的,因此实际上不需要同步。

仅当两个线程试图同时调用 getInstance() 时才需要同步(并且该方法在第一次调用时进行构造,而不是在 "static final" 时间)。

因此,我的问题基本上是:为什么您会更喜欢使用类似以下内容的单例的惰性构造:

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

我唯一的想法是,使用 static final 方法可能会引入顺序问题,就像 C++ 静态初始化顺序失败一样。

首先,Java 实际上这个问题吗?我知道一个类的顺序是完全指定的,但它是否以某种方式保证类之间的顺序一致(例如使用类加载器)?

其次,如果顺序一致的,为什么惰性构造选项永远是有利的?

最佳答案

Now, I think understand what this is doing. Since the instance is static final, it's built long before any threads will call getInstance() so there's no real need for synchronisation.

不完全是。它是在 SingletonHolder 类为 initialized 时构建的这发生在第一次调用 getInstance 时。类加载器有一个单独的锁定机制,但是在加载一个类之后,不需要进一步的锁定,所以这个方案做了足够的锁定来防止多次实例化。

First off, does Java actually have this problem? I know order within a class is fully specified but does it somehow guarantee consistent order between classes (such as with a class loader)?

Java 确实存在一个问题,即类初始化循环可能导致某些类在初始化之前(从技术上讲是在所有静态初始化程序 block 运行之前)观察另一个类的静态终结。

考虑

class A {
  static final int X = B.Y;
  // Call to Math.min defeats constant inlining
  static final int Y = Math.min(42, 43);
}

class B {
  static final int X = A.Y;
  static final int Y = Math.min(42, 43);
}

public class C {
  public static void main(String[] argv) {
    System.err.println("A.X=" + A.X + ", A.Y=" + A.Y);
    System.err.println("B.X=" + B.X + ", B.Y=" + B.Y);
  }
}

运行 C 打印

A.X=42, A.Y=42
B.X=0, B.Y=42

但是在您发布的成语中,助手和单例之间没有循环,因此没有理由更喜欢延迟初始化。

关于java - Java 有静态顺序初始化失败吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6606720/

相关文章:

c++ - 主线程中 block 作用域静态与命名空间作用域 thread_local 的初始化和销毁​​顺序

autotools - 在 Autoconf 测试中编译多个源文件

Java 文件不从头开始读取

swift - 如何更改 Realm 单例属性值

c++ - 一个有效的单例类?

android - 如何在所有 Activity 和 fragment 中使用 MediaPlayer 的单个实例?

java - 在不重新绘制树的情况下更新 JTree 中的 ImageIcon?

java - 单例设计和其中的新对象

java - Java 中的包和 C++ 中的库之间有区别吗

带有 thread_local 的 C++ Schwarz 计数器