0

在通过 SCJP6 考试模拟器时,我发现了这样的问题:

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);
        }}
    }

}

然后

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

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

答案说这段代码导致死锁,但我不明白——这到底是怎么可能的?有人可以帮我弄清楚吗?

4

2 回答 2

9

除了它不能编译之外,该代码中没有死锁。这段代码肯定会造成死锁:

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

因此,如果问题是:Clerk类会成为死锁的根源吗?那么答案是肯定的。

编辑

应该很快死锁的简短示例。如果在原始问题中使用 a 和 b,则程序运行良好。

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) {
                }
            }
        }
    }
}
于 2012-12-11T15:23:38.663 回答
3

如果一个线程是用 a/b 构造的,而第二个是用 b/a 构造的,我希望这会死锁。

在这种情况下,线程将锁定第一个实体,然后锁定第二个实体。如果线程 1 锁定 a 并试图锁定 b,同时线程 2 锁定 b 并等待 a,那么它将全部停止。

这是Java 教程死锁示例,与上面的示例非常相似。

于 2012-12-11T15:26:16.327 回答