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.
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.
In the entire program, the Static Initialization Block will execute only one time. There can be many Static Initialization Blocks in a specific class.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With