0

请问我可以知道下面的程序是否保证死锁吗?下面给出了详细信息: 线程:process1 和 process2。对象:扫描仪和打印机。process1 锁定扫描仪和打印机,但放弃扫描仪。process2 锁定扫描仪但无法获取打印机,因为 process1 已锁定它。也许我的线程概念不清楚,但是请我知道我哪里出错了?

class DeadLock extends Thread {

    //creating a scanner object
    private static Object scanner = new Object();

    //creating a printer object
    private static Object printer = new Object();

    //the process name
    private String processName;

    //initializes process2 is not created yet
    private boolean process2IsCreated = false;

    /**
     * the constructor which sets string to process1 or 2
     * @param string
     */
    public DeadLock(String string) {
        // TODO Auto-generated constructor stub
        this.processName  = string;
    }

    /**
     * deadlock() for process1
     */
    public void deadlock1() {

        //process1 locks scanner
        synchronized (scanner) {

            //process1 locks printer, too
            synchronized (printer) {

                //create process2 after process1
                if(process2IsCreated == false && processName.equals("process1")) {
                    new DeadLock("process2").start();
                    process2IsCreated = true;
                }

                try {
                    //process1 is waiting on scanner and releases its monitor. 
                    //After regaining access, process1 tries to acquire scanner
                    //but cannot do so because process2 has locked it already.
                    //. . .too late, process1!
                    scanner.wait();

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }
    }

    /**
     * deadlock() for process2
     */
    public void deadlock2() {

        //process2 locks scanner
        synchronized (scanner) {

            //process2 notifies process1 which is waiting on scanner
            scanner.notify();

            //process2 locks printer, but cannot lock printer because process1 has it
            //. . .too late, process2!
            synchronized (printer) {
            }
        }
    }

    /**
     * both threads are scheduled to execute run()
     */
    public void run() {

        //if process1 then enter deadlock1()
        if(processName.equals ("process1")) deadlock1();

        //if process 2 then enter deadlock2()
        else deadlock2();
    }

    /**
     * the main method which creates thread process1
     * @param a
     */
    public static void main(String a[]) {
        new DeadLock("process1").start();
    }
}
4

5 回答 5

2

这似乎对我有用,这是 Intellij 中的线程转储:

在此处输入图像描述

于 2013-11-14T23:05:13.590 回答
0

是的,这是一个几乎完美的死锁示例,原因如下(Oracle wait() 文档):

线程释放此监视器的所有权并等待,直到另一个线程通知等待此对象监视器上的线程唤醒[...]

所以监视器扫描仪被释放,但监视器打印机没有被释放。这就是为什么您不应该同步两次的原因。

您的代码只有一个问题,那就是虚假唤醒。可能会发生(尽管可能性很小),等待调用突然唤醒而没有人调用过通知。这更多是操作系统中锁定实现的原因,而不是与 Java 有任何关系,但是在正确的操作系统上运行,您的死锁可能最终会在几天、几个月或几年后唤醒。

于 2013-11-15T11:22:56.667 回答
0

看到这个..这里第二个线程正在启​​动

//create process2 after process1
                if(process2IsCreated == false && processName.equals("process1")) {
                    new DeadLock("process2").start();   <---------------HERE
                    process2IsCreated = true;
                }
于 2013-11-14T23:14:23.330 回答
0

我已经有一段时间没有使用 Java 的同步原语了,但对我来说它看起来像:

线程 1 锁定扫描仪。
线程 1 锁定打印机。
线程 2 启动。
线程 1 暂时释放扫描仪,休眠等待通知。
线程 2 锁定扫描仪。
线程 2 发布通知。
打印机上的线程 2 块。

线程 1 永远不会唤醒,因为线程 2 永远不会释放扫描仪。
线程 2 永远不会唤醒,因为线程 1 尚未使用打印机完成。

我的猜测是,您首先让线程 1 睡眠是错误的。它已经获得了两种资源,还等什么?

您也有可能过度使用同步;通常,简单的synchronized块(监视器)或wait/notify调用(信号量)可能就足够了。你两个都用。

认为这里的经验法则是,“如果您要使用wait/ notify,请将它们包装在最小的synchronized块中”。线程 2 中的扫描仪块超出了notify调用范围,进入了打印机块。

——
澄清:

synchronized (x) { A; }
synchronized (x) { B; }

是(使用)监视器,当您不希望 A 和 B 同时执行时。

synchronized (x) { x.wait(); } B;
A; synchronized (x) { x.notify(); }

使用信号量来确保 A 在 B 之前执行。

于 2013-11-15T00:05:56.893 回答
0
I guess, the flow is.. 
Thread 1 : takes scanner lock
Thread 1: takes printer lock
Thread 1: creates and starts 2nd thread

Possible flow: 

Thread 2 : Starts, executes run and goes into deadlock2()
Thread 1: waits for object scanner
Thread 2: Enters lock Scanner 
Thread 2: Notifies lock scanner
Thread 2: stuck as it cant get into printer block as Thread 1 has it
Thread 1: Is waiting for Thread 2 to leave scanner block which it does not.

Result: Thread 2 can not have Printer & Thread 1 can not start executing as Thread 2 even when it is notified scanner , has not left Scanner block.

This is not a proper deadlock as thread 1 has not returned for execution.
于 2013-11-14T23:24:12.143 回答