开发者

Class initialization and synchronized class method

In my application, there is a class like below:

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

    static {
        doSomething(); // which will开发者_如何学C take some time to complete
    }
}

This class will be used in a multi thread environment, many threads may call the Client.print() method simultaneously. I wonder if there is any chance that thread-1 triggers the class initialization, and before the class initialization complete, thread-2 enters into print method and print out the "hello" string?

I see this behavior in a production system (64 bit JVM + Windows 2008R2), however, I cannot reproduce this behavior with a simple program in any environments.

In Java language spec, section 12.4.1 (http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html), it says:

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the reference to the field is not a compile-time constant (§15.28). References to compile-time constants must be resolved at compile time to a copy of the compile-time constant value, so uses of such a field never cause initialization.

According to this paragraph, the class initialization will take place before the invocation of the static method, however, it is not clear if the class initialization need to be completed before the invocation of the static method. JVM should mandate the completion of class initialization before entering its static method according to my intuition, and some of my experiment supports my guess. However, I did see the opposite behavior in another environment. Can someone shed me some light on this?

Any help is appreciated, thanks.


My understanding of the quoted text is that the class initialization process is completed (will be initialized) before a static method declared by T is invoked.

will be initialized implies that the initialization process has been started and has terminated.

So it shouldn't be possible (to my understanding) that, while the static initializer is executed because Thread A called print, another Thread already can call print.

Chapter 12.4.2 of the JLS describes the detailed initialization procedure, which takes care of initializing classes in a multithreaded environment.


Executing static blocks considered to be a part of class initialization:

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class...

It is guaranteed by JVM specification that that will be done in thread safe way. To quote JLS section 12.4.2 Detailed Initialization Procedure:

Because the Java programming language is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface; for example, a variable initializer in class A might invoke a method of an unrelated class B, which might in turn invoke a method of class A. The implementation of the Java virtual machine is responsible for taking care of synchronization and recursive initialization...

In more detail, it's implemented by acquiring lock on Class object:

The procedure for initializing a class or interface is then as follows:

  1. Synchronize (§14.19) on the Class object that represents the class or interface to be initialize

Your method is static synchronized and it requires lock on Class object as well. Since the same lock is acquired by JVM during class initialization it's not possible for one thread to initialize class and for other execute static synchronized method on it. All quotes are taken from JLS I hope that's helpful. Btw, how do you know that print occurs before class initialization finishes?

EDIT: Actually I'm wrong about assumption that only static synchronized couldn't be executed in parallel with class initialization. Any methods on class couldn't be executed until class initialization finishes.


If your "multi thread environment" uses multiple class loaders to load your Client class it would be possible for you to get mulitple Client instances, each one of which would run the static initialiser prior to running any Client.print() calls. You would see something like

doSomething
hello
doSomething
hello
hello
hello

I have some sample code which shows this but the current version is a little fiddly to run. If you want I can clean it up and post it.


If the code is running in some containers such as Servlet, you could initialize it in container’s lifecycle.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜