Java: Why is this a Deadlock when lock is null?

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
.
.
.
Jon Skeet
people
quotationmark

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.

people

See more on this question at Stackoverflow