Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Program hangs if thread is created in static initializer block

Tags:

I have come across a situation where my program hangs, looks like deadlock. But I tried figuring it out with jconsole and visualvm, but they didn't detect any deadlock. Sample code:

public class StaticInitializer {

private static int state = 10;

static {
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            state = 11;
            System.out.println("Exit Thread");
        }
    });

    t1.start();

    try {
        t1.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    System.out.println("exiting static block");
}

public static void main(String...strings) {
    System.out.println(state);
}
}

When I execute this in debug mode then I could see control reaching @Override public void run() { state = 11;

but as soon as state=11 is executed it just hangs/deadlocks. I looked in different postings in stackoverflow and I thought that static initializers are thread-safe but in that case jconsole should report this. About main thread, jconsole saying that it is in waiting state, and that's fine. But for the thread created in static initializer block, jconsole says that it is in RUNNABLE state and not blocked. I am confused and here lacking some concept. Please help me out.

like image 696
thomas Avatar asked Sep 22 '11 16:09

thomas


People also ask

Are static initializers thread safe?

A static initializer only gets called once, so by that definition it's thread safe -- you'd need two or more invocations of the static initializer to even get thread contention.

How many times static initializer block is executed?

In the entire program, the Static Initialization Block will execute only one time. There can be many Static Initialization Blocks in a specific class.

What is the difference between static block and instance initializer block?

Static blocks can be used to initialize static variables or to call a static method. However, an instance block is executed every time an instance of the class is created, and it can be used to initialize the instance data members.

Why do we use static initializer block in Java?

Java For Testers Instance variables are initialized using initialization blocks. However, the static initialization blocks can only initialize the static instance variables. These blocks are only executed once when the class is loaded.


1 Answers

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.

like image 100
Jon Skeet Avatar answered Oct 31 '22 08:10

Jon Skeet