Java - 使用wait()和notify()

时间:2013-01-17 23:51:15

标签: java multithreading deadlock

这不是Java, Multithreading with synchronized methods的重复......他没有问同样的问题。

我正在尝试编写一个使用多线程和死锁的程序。我无法理解在我的synchronized方法中如何以及在何处使用wait()和notify()来让线程等待并使用notify()将其唤醒。我让它在ping语句之后使第一个线程等待,所以下一个线程也将启动它的ping语句。但我有一个notify()唤醒第一个线程,我无法弄清楚为什么线程不会唤醒。以下是我的输出:

Starting...1
Girl (ping): pinging Boy
Boy (ping): pinging Girl
Girl (ping): asking Boy to confirm
Boy (confirm): confirm to Girl
Girl (ping): got confirmation
Boy (ping): asking Girl to confirm
Girl (confirm): confirm to Boy
Boy (ping): got confirmation

我的代码是死锁,或者我没有正确使用等待和通知,因为它停在这里:

Starting...1
Girl (ping): pinging Boy
Boy (ping): pinging Girl
Girl (ping): asking Boy to confirm
Boy (confirm): confirm to Girl
Girl (ping): got confirmation

这是我的代码:

Monitor.java

class Monitor {
String name;

   public Monitor (String name) { this.name = name; }

   public String getName() {  return this.name; }

   public synchronized void ping (Monitor p) {
      p.release(p);
      System.out.println(this.name + " (ping): pinging " + p.getName());
      notify();
      try { wait(); } catch (Exception e) {}
      System.out.println(this.name + " (ping): asking " + p.getName() + " to confirm");
      p.confirm(p);
      System.out.println(this.name + " (ping): got confirmation");
   }

   public synchronized void confirm (Monitor p) {
      System.out.println(this.name + " (confirm): confirm to " + p.getName());
   }

   public synchronized void release (Monitor p) {
      notify();
   }
}

Runner.java

public class Runner extends Thread {
Monitor m1, m2;

    public Runner (Monitor m1, Monitor m2) { 
      this.m1 = m1; 
      this.m2 = m2; 
    }

    public void run () {  
       m1.ping(m2);  
    }
}

Deadlock.java

public class DeadLock {
   public static void main (String args[]) {
      int i=1;
      System.out.println("Starting..."+(i++));
      Monitor a = new Monitor("Girl");
      Monitor b = new Monitor("Boy");
      (new Runner(a, b)).start();
      (new Runner(b, a)).start();
   }
}

2 个答案:

答案 0 :(得分:1)

您正在致电:

(new Runner(a, b)).start();
// which effectively calls in run()
a.ping(b);

此锁定a会在a上调用通知,然后等待a

另一个线程调用:

(new Runner(b, a)).start();
// which effectively calls in run()
b.ping(a);

此锁定b会在b上调用通知,然后等待b

由于两个线程都没有通知另一个线程,因此它们永远不会离开该状态。我不确定你要完成什么,所以很难弄清楚如何修复代码。

修改

现在你已经编辑了代码,你有一个更标准的死锁。

  • 第一个线程锁定a然后尝试锁定b以通知它。
  • 第二个线程锁定b然后尝试锁定a以通知它。

每个线程都有锁,但需要另一个锁才能继续。经典僵局。

我建议您学习使用调试器@ OhioState22。设置断点并逐步执行代码。这是一个不错的Eclipse tutorial

答案 1 :(得分:0)

通常避免使用Java的wait()和notify(),而是选择Java 5的并发功能之一,例如ReentrantLock的。原因是如果一个线程在你的线程命中wait()之前调用notify(),那么对wait()的后续调用将会无限期地阻塞并取决于你的算法。查找RenetrantLock

的javadoc