2013-04-20 186 views
0

我的任何notifyAll()方法似乎都不起作用。 露西假设等到鲍勃到达然后释放。 鲍勃正在等待露西的承认,然后释放。 这些事情似乎都没有发生。为什么我的notify()不起作用?

有人可以让我知道我做错了什么,我可以如何解决它。 在此先感谢。

编辑 - 我使用Grays的建议修改了我的代码。 异常消失,但notify()方法仍然不起作用。

import java.util.logging.Level; 
import java.util.logging.Logger; 

public class PlayDates { 
    Thread lucyThread; 
    Girl lucy; 
    Thread bobThread; 
    Boy bob; 

    public static void main(String[] args) { 
     PlayDates playDates = new PlayDates(); 
     playDates.run(); 
    } 
    public void run() { 
     lucy = new Girl(); 
     lucyThread = new Thread(lucy); 

     bob = new Boy(); 
     bobThread = new Thread(bob); 

     lucyThread.start(); 
     threadSleep(500); 
     bobThread.start(); 
    } 

    public class Girl implements Runnable { 
     @Override 
     public void run() { 
      synchronized(PlayDates.this){ 
       System.out.println("Girl synchronized hit"); 
       if(!bob.hasArrived()) {  // Doesnt seem to get past here? 
        System.out.println("Lucy has fallen asleep waiting for Bob"); 
        try { 
         PlayDates.this.wait(); // Wait for Bob 
         System.out.println("Lucy has woken up"); 
         PlayDates.this.notifyAll();  // Acknowledge Bobs arrival 
        } catch (InterruptedException ex) { 
         Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex); 
        } 
       } 
      } 
     } 
    } 

    public class Boy implements Runnable { 
     private boolean hasArrived; 

     @Override 
     public void run() { 
      synchronized(PlayDates.this){ 
       System.out.println("Bob has arrived to play"); 
       PlayDates.this.notifyAll(); 
       try { 
        PlayDates.this.wait(); // Wait for Lucy to acknowledge Bobs arrival 
       } catch (InterruptedException ex) { 
        Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex); 
       } 

       System.out.println("Bob and Lucy are playing"); 
      } 
     } 

     public Boy() { 
      hasArrived = true; 
     } 

     public boolean hasArrived() { 
      return hasArrived; 
     } 
    } 

    public void threadSleep(int milli) { 
     try { 
      Thread.sleep(milli); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

电流输出

Girl synchronized hit 
Bob has arrived to play 

编辑2 我已经适应我的代码为灰色意见认为。 hasArrived现在不稳定,并在playDates运行方法。 在内部类Boys运行方法中将其更改为true。 输出没有改变,问题看起来是一样的。 还有什么建议吗?

更新代码:

import java.util.logging.Level; 
import java.util.logging.Logger; 

public class PlayDates { 
    Thread lucyThread; 
    Girl lucy; 
    Thread bobThread; 
    Boy bob; 
    volatile boolean hasArrived; 

    public static void main(String[] args) { 
     PlayDates playDates = new PlayDates(); 
     playDates.run(); 
    } 
    public void run() { 
     hasArrived = false; 
     lucy = new Girl(); 
     lucyThread = new Thread(lucy); 

     bob = new Boy(); 
     bobThread = new Thread(bob); 

     lucyThread.start(); 
     threadSleep(500); 
     bobThread.start(); 
    } 

    public class Girl implements Runnable { 
     @Override 
     public void run() { 
      synchronized(PlayDates.this){ 
       System.out.println("Girl synchronized hit"); 
       if(hasArrived) {  // Doesnt seem to get past here? 
        System.out.println("Lucy has fallen asleep waiting for Bob"); 
        try { 
         PlayDates.this.wait(); // Wait for Bob 
         System.out.println("Lucy has woken up"); 
         PlayDates.this.notifyAll();  // Acknowledge Bobs arrival 
        } catch (InterruptedException ex) { 
         Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex); 
        } 
       } 
      } 
     } 
    } 

    public class Boy implements Runnable { 
     @Override 
     public void run() { 
      threadSleep(1000); 
      synchronized(PlayDates.this){ 
       System.out.println("Bob has arrived to play"); 
       hasArrived = true; 
       PlayDates.this.notifyAll(); 
       try { 
        PlayDates.this.wait(); // Wait for Lucy to acknowledge Bobs arrival 
       } catch (InterruptedException ex) { 
        Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex); 
       } 
       System.out.println("Bob and Lucy are playing"); 
      } 
     } 
    } 

    public void threadSleep(int milli) { 
     try { 
      Thread.sleep(milli); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 
+0

如果你正在编辑@James所有的时间,这个问题很难回答。它使我们的答案无效。这不应该是一个论坛。 – Gray 2013-04-20 18:08:21

+0

@格雷我道歉,我是新的。 今后,我应该问一个新的问题与修改后的代码? – James 2013-04-20 18:10:46

+0

你可以编辑你的答案,并添加一个新的部分到最后。 – Gray 2013-04-20 18:14:09

回答

3

要启动Girl线程在初始化bob领域,所以你会得到一个NPE之前。您应该在Girl之前初始化您的bob字段,并将其传递到该线程。你的程序可能在某些情况下工作,但有一个不可预测的竞争条件。如果线程启动得足够快,它可能会工作,但您应该在之前初始化bob线程,启动Girl线程。

您也有一些memory synchronization issues。例如,尽管您在PlayDates.this上进行同步,但当Girl线程调用bob.hasArrived()时,Boy类可能尚未初始化和同步。无论何时在多个线程中访问字段,都需要确保两个线程都看到正确同步的值。您可以通过将hasArrived设置为AtomicBoolean或将hasArrived标记为volatile来确保这一点。

编辑:

的问题是不断变化的,所以我会尽力跟上。我会推荐而不是设置hasArrivedBoy构造函数中为true。我认为你应该把它做成volatile并在run()方法中设置。你想要Girl线程启动,运行一下,然后看到Boy不可用和wait()。所以Boy线程应该稍后开始,并且在sleep()之后将hasArrived设置为truerun()方法。

+0

我想让我的女孩领域等待Bob领域。 我已经使用你的建议修改了我的代码,这样NPE不再被抛出,但通知方法仍然不工作。 – James 2013-04-20 18:05:29

+0

你只需要在你的'女孩'线程@James上调用'start()''构造'Bob'类。 – Gray 2013-04-20 18:07:09

+0

我的答案的第二部分可能会帮助您解决同步问题@James。 – Gray 2013-04-20 18:09:45