Java是否有静态订单初始化惨败? [英] Does Java have the static order initialisation fiasco?

查看:150
本文介绍了Java是否有静态订单初始化惨败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

A recent question here had the following code (well, similar to this) to implement a singleton without synchronisation.

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

现在,我想了解这是做什么的。由于实例是静态最终,所以在任何线程调用 getInstance()之前很久就会构建它,因此不需要同步。

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.

只有当两个线程试图同时调用 getInstance()时才需要同步(和该方法在第一次调用时进行构建,而不是在静态最终时间)。

Synchronisation would be needed only if two threads tried to call getInstance() at the same time (and that method did construction on first call rather than at "static final" time).

因此我的问题基本上是:那么为什么你更喜欢单身人士的懒惰建构,例如:

My question is therefore basically: why then would you ever prefer lazy construction of the singleton with something like:

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 ++静态初始化顺序fiasco。

My only thoughts were that using the static final method may introduce sequencing issue as in the C++ static initialisation order fiasco.

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

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)?

其次,如果订单 一致,为什么延迟构造选项会有利?

Secondly, if the order is consistent, why would the lazy construction option ever be advantageous?

推荐答案


现在,我想了解这是做什么的。由于实例是静态final,所以在任何线程调用getInstance()之前很久就会构建它,因此不需要同步。

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.

Not相当。它是在 SingletonHolder 类是初始化,这是第一次调用 getInstance 时调用。类加载器有一个单独的锁定机制,但是在加载一个类之后,不需要进一步锁定,所以这个方案只进行了足够的锁定以防止多次实例化。

Not quite. It is built when the SingletonHolder class is initialized which happens the first time getInstance is called. The classloader has a separate locking mechanism, but after a class is loaded, no further locking is needed so this scheme does just enough locking to prevent multiple instantiation.


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

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确实存在一个问题,即类初始化周期可能导致某些类在初始化之前观察另一个类的静态终结(技术上在所有静态初始化程序块运行之前)。

Java does have a problem where a class initialization cycle can lead to some class observing another class's static finals before they are initialized (technically before all static initializer blocks have run).

考虑

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

但是在你发布的成语中,助手和单身之间没有循环,因此没有理由倾向于延迟初始化。

But in the idiom you posted, there is no cycle between the helper and the singleton so there is no reason to prefer lazy initialization.

这篇关于Java是否有静态订单初始化惨败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆