如何通过wait / notify编写保证死锁

时间:2017-01-03 10:01:59

标签: java multithreading concurrency deadlock wait

我最近访问了一些采访。采访者让我写保证死锁。

我写了以下内容:

public class DeadLockThreadSleep {
    private static class MyThread implements Runnable {
        private Object o1;
        private Object o2;

        @Override
        public void run() {
            try {
                test(o1, o2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public MyThread(Object o1, Object o2) {
            this.o1 = o1;
            this.o2 = o2;
        }

        public void test(Object o1, Object o2) throws InterruptedException {
            synchronized (o1) {
                System.out.println("1.acquired: " + o1);
                Thread.sleep(1000);
                synchronized (o2) {
                    System.out.println("2.acquired: " + o2);

                }
            }
        }
    }

    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();
        new Thread(new MyThread(o1, o2)).start();
        new Thread(new MyThread(o2, o1)).start();

    }
}

然后他问我是否确定它是有保障的。我记得Thread.sleep没有任何保证。

然后我写了这段代码:

public static void main(String[] args) {
        final Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mainThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

这个答案被接受了。

他还要求通过wait / notify编写模拟。我想了很多,我无法想象如何写这个。

有可能吗?

2 个答案:

答案 0 :(得分:1)

这可以通过创建一个循环来完成,其中一个线程持有资源并等待另一个资源,而另一个线程以相反的顺序执行相同的操作。

主题t持有resourceOne并等待resourceTwo,而t1持有resourceTwo并等待resourceOne

以下是示例代码:

    public class WaitNotifyLock {

        boolean isONHold = false;
        public synchronized void hold(){
            while(isONHold){
                try {
                    wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        isONHold = true;
        System.out.println(Thread.currentThread().getId() + " : Holded");
    }

    public synchronized void unHold(){
        while(!isONHold){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getId() + " : Produced");
        isONHold = false;
        notify();
    }

    public static void main(String[] args) {
        WaitNotifyLock resourceOne =  new WaitNotifyLock();
        WaitNotifyLock resourceTwo =  new WaitNotifyLock();
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                resourceOne.hold();
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                resourceTwo.hold();
                resourceOne.unHold();
                resourceTwo.unHold();
            }
        });

        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                resourceTwo.hold();
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                resourceOne.hold();
                resourceTwo.unHold();
                resourceOne.unHold();
                }
            });

            t.start();
            t1.start();
        }

    }

答案 1 :(得分:1)

死锁是所谓的活着危险(其他人是饥饿,反应不佳或活锁),可以考虑两种主要类型:

  • 锁定命令死锁
  • 资源死锁

但是,Java documentation将其简化如下:

  

死锁描述了两个或多个线程永远被阻塞,等待彼此的情况。

因此,恕我直言,你可以简单地用这个来强制执行死锁:

public class DeadlockDemo {

    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();

        new Thread(() -> waitLeftNotifyRight(a, b)).start();
        waitLeftNotifyRight(b, a);
    }

    public static void waitLeftNotifyRight(Object left, Object right) {
        synchronized (left) {
            try {
                System.out.println("Wait");
                left.wait();
            } catch (InterruptedException e) { /* NOP */ }
        }
        synchronized (right) {
            System.out.println("Notify");
            right.notify();
        }
    }

}

此演示永远不会终止,因为创建的线程在a的监视器上等待,而主线程在b的监视器上等待。因此,不会调用相应的notify()方法(这会终止程序)。