I was having a deadlock scenario in my code. I reproduced the scenario with the following test code (look at the line number comments too).
I have one ExecuterService
which takes 3 tasks, 2 tasks have a synchronized block over the same object which is not initialized it should have the null
value.
synchronized(null){}
is not allowed in java so I was expecting an error at line-2
. However, this executed with a deadlock. i.e. the first two tasks were kept waiting by the 3rd task. (see Output-1)
Now If I change line-1
to Object lock = new Object();
The code will work flawlessly without any deadlock(Output-2). I am just wondering what exactly is happening with JVM when we provide an uninitialized mutex object? Looks like JVM is creating a static copy for the same, which shared by all the tasks. Hence the deadlock
public class Test {
Object lock; //line -1
Integer a = 10;
public static void main(String[] arg) {
new Test().doIt();
}
public void doIt() {
ExecutorService service = Executors.newFixedThreadPool(3);
service.submit(new Runnable() {
public void run() {
synchronized (Test.this.lock) { //line -2
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Test.this.a = (int) Thread.currentThread().getId();
System.out.println(a + " " + Thread.currentThread().getId());
}
}
});
service.submit(new Runnable() {
public void run() {
synchronized (Test.this.lock) {
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Test.this.a = (int) Thread.currentThread().getId();
System.out.println(a + " " + Thread.currentThread().getId());
}
}
}
);
service.submit(new Runnable() {
public void run() {
Test.this.a = (int) Thread.currentThread().getId();
while (true) {
try {
Thread.sleep(1 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(a + " Main");
}
}
});
}
}
Output -1
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
.
.
.
Output-2
11 Main
11 Main
11 Main
11 Main
9 9
9 Main
9 Main
9 Main
9 Main
9 Main
10 10
10 Main
10 Main
.
.
.
You don't have a deadlock - there's an error just as you expected. The first and second tasks will throw NullPointerException
, leaving only the third task running.
You can see this if you surround the body of run()
in a try
/catch
statement.
See more on this question at Stackoverflow