javascjp

How can this code cause deadlock?


While passing SCJP6 exam simulator I found question like this:

class Clerk implements Runnable {

    private Record A, B;

    public Clerk(Record a, Record b) {
        A = a;
        B = b;
    }

    public void run() {
        while(true) {
            doStuff(A, B);
        }
    }

    public synchronized void doStuff(Record a, Record b) {
        synchronized(a) {
        synchronized(b) {
            a.add(1);
            b.add(-1);
        }}
    }

}

then

Record a = new Record();
Record b = new Record();

new Thread(new Clerk(a, b)).start();
new Thread(new Clerk(a, b)).start();

Answer says that this code can cause deadlock, but I don't get it - how exactly is that possible? Can someone can help me figure that out?


Solution

  • Apart from the fact that it does not compile, there is no deadlock in that code. This code could definitely create a deadlock:

    new Thread(new Clerk(a, b)).start();
    new Thread(new Clerk(b, a)).start();
    

    So if the question is: could the Clerk class be the source of the deadlock? Then the answer is yes.

    Short example that should deadlock fairly fast. If a and b are used like in the original question, the program runs fine.

    public class Test1 {
    
        public static void main(String[] args) {
            Record a = new Record();
            Record b = new Record();
    
            new Thread(new Clerk(a, b)).start();
            new Thread(new Clerk(b, a)).start();
        }
    
        static class Record {
        }
    
        static class Clerk implements Runnable {
    
            private Record A, B;
    
            public Clerk(Record a, Record b) {
                A = a;
                B = b;
            }
    
            public void run() {
                while (true) {
                    System.out.println("in thread " + Thread.currentThread());
                    for (int i = 0; i < 10000; i++) {
                        doStuff(A, B);
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                    }
                }
            }
    
            public synchronized void doStuff(Record a, Record b) {
                synchronized (a) {
                    synchronized (b) {
                    }
                }
            }
        }
    }