【问题标题】:Thread safety between static methods and a static block [duplicate]静态方法和静态块之间的线程安全[重复]
【发布时间】:2017-05-21 12:55:50
【问题描述】:

在多线程环境中,一个类的静态块是否保证在调用其他静态方法(在同一类中)之前完成?

我的意思不是静态块本身调用其他静态方法。为了澄清,我们可以使用下面的代码块。

外部类能否启动两个线程,这两个线程都调用OurClass.doSomething(),其中一个线程将在静态块完成之前开始执行?

public class OurClass {

    static {
    // does something that takes a long time
    }

    public static void doSomething() {
    // can I be called before the block has finished?
    }
}

【问题讨论】:

  • 如果静态块本身调用任何静态方法怎么办?
  • 这取决于。请给出一个具体的代码作为例子。

标签: java multithreading static thread-safety


【解决方案1】:

外部类是否可以启动两个线程,这两个线程都调用 OurClass.doSomething(),其中一个将在 静态块完成了吗?

不,这在 Java 的兼容实现中是不可能的。

section 12.4.1 of the Java Language Specification:

类或接口类型 T 将在紧接之前初始化 以下任何一项的第一次出现:

  • T 是一个类,并创建了一个 T 的实例。

  • 调用了由 T 声明的静态方法。

  • 分配了一个由 T 声明的静态字段。

  • 使用了由 T 声明的静态字段,并且该字段不是常量变量(第 4.12.4 节)。

  • T 是一个顶级类(第 7.6 节),并且会执行在词法上嵌套在 T(第 8.1.3 节)中的断言语句(第 14.10 节)。

section 12.4 just above this text 描述了“初始化类类型 T”的含义:

类的初始化包括执行其静态 初始化器和静态字段(类变量)的初始化器 在类中声明。


有关类初始化的多线程/内存模型含义的更多详细信息,需要阅读第 12.4.2 节 ("12.4.2. Detailed Initialization Procedure")。

总之,本节解释说,每当 Java 想要使用特定的 C 类时,它需要*就像它在该类 C* 上获得了同步锁 LC

然后需要检查类是否已经初始化。只有在类已完全初始化时,它才能对该类进行任何操作。如果它还没有被初始化,并且它没有被另一个线程初始化,那么它此时需要初始化这个类。

特别是您的评论,第 12.4.2 节指出,一旦它在类上具有此同步锁:

如果 C 的 Class 对象指示初始化正在进行中 对于当前线程的 C,那么这必须是一个递归请求 初始化。释放LC并正常完成。

【讨论】:

  • (首先,感谢您提供指向规范中正确位置的链接)。但是,这种描述似乎与上面@Eran 所写的情况相矛盾,其中静态块调用静态方法(确实会在静态块完成之前执行)。
  • 这很接近,看起来血腥的细节在 12.4.2 中
  • @NathanHughes 是的,我只是想总结一下12.4.2的细节
  • @Eyal 更新答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-10
相关资源
最近更新 更多