I encountered a lock problem in my application, which contains several classes, as shown below:
public interface AppClient { void hello(); } public class Client implements AppClient { public synchronized static AppClient getInstance() { return instance; } public void hello() { System.out.println("Hello Client"); } private final static class InnerClient implements AppClient { public void hello() { System.out.println("Hello InnerClient"); } } private static AppClient instance; static { instance = new InnerClient(); doSomethingThatWillCallClientGetInstanceSeveralTimes(); } } public class Application { new Thread() { AppClient c = Client.getInstance(); c.hello(); }.start(); new Thread() { AppClient c = Client.getInstance(); c.hello(); }.start();
In the doSomethingThatWillCallClientGetInstanceSeveralTimes () method, it will perform quite a few initialization operations involving many classes and cyclically call the static Client.getInstance method several times during initialization (I understand that this is not good, but this is an outdated code base that lasts more than 20 years).
Here is my problem:
1) I thought that until the Client class was initialized, only the first thread that started the Client class initialization can access the Client.getInstance method, because the JVM will synchronize in the Client.class object until the class is initialized. I read JLS on the relevant topic and came to this conclusion (section 12.4.2, Detailed Initialization Procedure, http://java.sun.com/docs/books/jls/third_edition/html/execution.html ).
2) However, this was not the behavior that I saw in my real environment. For example, there are three threads that call Client.getInstance (), thread-1 starts the initialization of Client.class and calls the client.getInstance () method in doSomethingThatWillCallClientGetInstanceSeveralTimes () several times. And until the doSomethingThatWillCallClientGetInstanceSeveralTimes () method is completed, thread-2 receives a lock on the Client.class object (as possible, but it happened) and enters the Client.getInstance method (since this method is a static synchronized method), For some reason, thread-2 cannot return an "instance" (I think it waits for Client.class to complete its initialization). At the same time, thread-1 cannot continue, because you still need to call Client.getInstance in doSomethingThatWillCallClientGetInstanceSeveralTimes () and cannot get a lock because it belongs to thread-2. Threaddump tells me that thread-2 is in RUNNABLE state and thread-1 is in BLOCKED state, waiting for a lock belonging to thread-2.
I can only reproduce this behavior in the 64-bit Java 6u23 JVM on Windows and I cannot reproduce the 32-bit Java 6 JVM + Windows environment. Can someone tell me what I am missing here? Is this kind of code doomed to cause such a lock, if so, why? Is my understanding of JLS wrong for this part? Or is this a JVM problem? Any help is appreciated. Thanks.