类初始化和同步类方法

nyb*_*bon 7 java concurrency multithreading synchronization

在我的应用程序中,有一个类如下:

public class Client {
    public synchronized static print() {
        System.out.println("hello");
    }

    static {
        doSomething(); // which will take some time to complete
    }
}
Run Code Online (Sandbox Code Playgroud)

此类将在多线程环境中使用,许多线程可以同时调用Client.print()方法.我想知道线程1是否有可能触发类初始化,并且在类初始化完成之前,thread-2进入print方法并打印出"hello"字符串?

我在生产系统(64位JVM + Windows 2008R2)中看到了这种行为,但是,我无法在任何环境中使用简单程序重现此行为.

在Java语言规范的第12.4.1节(http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html)中,它说:

类或接口类型T将在第一次出现以下任何一个之前立即初始化:

  • T是一个类,并且创建了T的实例.
  • T是一个类,并且调用由T声明的静态方法.
  • 分配由T声明的静态字段.
  • 使用由T声明的静态字段,对字段的引用不是编译时常量(第15.28节).编译时常量的引用必须在编译时解析为编译时常量值的副本,因此使用这样的字段永远不会导致初始化.

根据这一段,类初始化将在静态方法的调用之前进行,但是,不清楚是否需要在调用静态方法之前完成类初始化.根据我的直觉,JVM应该在进入静态方法之前完成类初始化,并且我的一些实验支持我的猜测.但是,我确实在另一个环境中看到了相反的行为.有人能否对我有所了解?

任何帮助表示赞赏,谢谢.

And*_*s_D 4

我对引用文本的理解是,类初始化过程在调用 T 声明的静态方法之前完成(初始化)。

将被初始化意味着初始化过程已开始并已终止。

print因此,根据我的理解,当由于线程 A 调用而执行静态初始化程序时,另一个线程已经可以调用 ,这是不可能的print

JLS 的第 12.4.2 章描述了详细的初始化过程,该过程负责在多线程环境中初始化类。