保证死锁

时间:2013-11-14 22:57:29

标签: java multithreading deadlock

请问,请知道以下程序是否可以保证死锁?以下是详细信息: 线程: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();
    }
}

5 个答案:

答案 0 :(得分:2)

这似乎对我有用,这里是Intellij中的Thread Dump:

enter image description here

答案 1 :(得分:0)

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

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

答案 2 :(得分: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.

答案 3 :(得分: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之前执行。

答案 4 :(得分:0)

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

  

线程发布   监视器的所有权,并等待另一个线程通知   在此对象的监视器上等待的线程唤醒[...]

因此显示器扫描仪已释放,但显示器打印机未释放。这就是你不应该两次同步的原因。

您的代码只有一个问题,即spurious wakeups。它可能发生(虽然它不太可能),等待呼叫突然醒来,没有人曾经通知过。这更多是操作系统中锁定实现的原因,而不是与Java有关,但是在正确的操作系统上运行,您的死锁最终可能会在几天,几个月或几年后醒来。