Program hangs if thread is created in static initializer block

不打扰是莪最后的温柔 提交于 2019-11-27 01:08:04

You're not just starting another thread - you're joining on it. That new thread has to wait for StaticInitializer to be fully initialized before it can proceed, because it's trying to set the state field... and initialization is already in progress, so it waits. However, it's going to be waiting forever, because that initialization is waiting for that new thread to terminate. Classic deadlock.

See the Java Language Specification section 12.4.2 for details about what's involved in class initialization. Importantly, the initializing thread will "own" the monitor for StaticInitializer.class, but the new thread will be waiting to acquire that monitor.

In other words, your code is a bit like this non-initializer code (exception handling elided).

final Object foo = new Object();
synchronized (foo)
{
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (foo) {
                System.out.println("In the new thread!");
            }
        });
    t1.start();
    t1.join();
});

If you can understand why that code would deadlock, it's basically the same for your code.

The moral is not to do much work in static initializers.

classloading is kind of a sensitive time in the jvm. when classes are being initialized, they hold an internal jvm lock which will pause any other thread trying to work with the same class. so, your spawned thread is most likely waiting for the StaticInitializer class to be fully initialized before proceeding. however, your StaticInitializer class is waiting for the thread to complete before being fully initialized. thus, deadlock.

of course, if you are truly trying to do something like this, the secondary thread is superfluous since you are joining it right after you start it (so you might as well just execute that code directly).

UPDATE:

my guess as to why the deadlock is not detected is because it is occurring at a much lower level than the level at which the standard deadlock detection code works. that code works with normal object locking, whereas this is deep jvm internal stuff.

I was able to get your program to run by commenting out the line state = 11;

You can not set state=11 until you have completed initialization. You can not complete initialization until t1 finishes running. T1 can not finish running until you set state=11. Deadlock.

Here is what I think happens:

  1. The main thread tries to initialize StaticInitializer. This involves locking the corresponding Class object.
  2. While still holding the lock, the main thread spawns another thread, and waits for it to terminate.
  3. The other thread's run() method attempts to access state, which requires StaticInitializer to be fully initialized; this involves waiting on the same lock as in step 1.

End result: a deadlock.

See the JLS for a detailed description of the intialization procedure.

If you move t1.join() into main(), everything works.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!