2011-04-11 82 views
1

下面是代码的一部分。我很困惑为什么“通知1”不能真正唤醒正在等待的另一个功能。java多线程问题

它与接缝有关: 当一个线程正在为一个对象执行一个同步方法时,所有其他线程调用同一对象的同步方法块(暂停执行),直到第一个线程完成对象。

为什么结果不是: 等待, notify1, 等待完成, notify2, 。 。 。

取而代之的则是: 等待, notify1, notify2, notify2, 。 。 。 notify2, 通知2, 通知3, 等待光洁度, 跳过等待, 跳过等待, 跳过等待, 。 。 。

代码 { 。 。 。

MultiThreadContent m; 

    void divideToParts(File testFile,FileInputStream fileInputStream, Object hashMachine) throws IOException, InterruptedException{ 

     . 
     . 
     . 
     //run from here 
     m = new MultiThreadContent(fileInputStream,(int)temp23,(int) (testFile.length()%temp23), numberOfParts, hashMachine); 
     new Thread(new Read()).start(); 
     m.update(); 
    } 

    class Read implements Runnable{ 
     @Override 
     public void run() { 
      try { 
       m.read(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    class MultiThreadContent{ 

     . 
     . 
     . 


     boolean preNotReady=true; 
     boolean updateNotFinished; 

     //read{ 
      public synchronized void read() throws InterruptedException{ 
       //initial{ 
        readNextBlock(); 
        preBlock=nextBlock; 
        read_notify(); 
        System.out.println("notify 1");//d 
        if(finishedRead!=true) 
        { 
         readNextBlock(); 
         read_wait(); 
        } 
        else 
         return; 
       //} 
       while(finishedRead!=true){ 
        preBlock=nextBlock; 
        read_notify(); 
        System.out.println("notify 2");//d 
        readNextBlock(); 
        read_wait(); 
       } 
       //closing{ 
        preBlock=nextBlock; 
        read_notify(); 
        System.out.println("notify 3");//d 
       //} 
      } 
      void read_notify(){ 
       preNotReady=false; 
       notifyAll(); 
      } 
      void read_wait() throws InterruptedException{ 
       if(updateNotFinished==true) 
       { 
        wait(); 
        System.out.println("wait for update");//d 
       } 
       preNotReady=true; 
      } 
     //} 


     //update{ 
      public synchronized void update() throws InterruptedException{ 
       for (int i = 0; i < totalParts; i++) { 
        update_wait(); 
        divideToParts_update(hashMachine, preBlock); 
        update_notify(); 
       } 
      } 
      void update_notify(){ 
       updateNotFinished=false; 
       notifyAll(); 
      } 
      void update_wait() throws InterruptedException{ 
       if(preNotReady){ 
        System.out.println("wait");//d 
        wait(); 
        System.out.println("wait finish");//d 
       } 
       updateNotFinished=true; 
       System.out.println("skip wait");//d 
      } 
     //} 
    } 
} 
+1

'finishedRead'没有定义?这是所有的代码? – Kevin 2011-04-11 13:58:38

+0

它是代码的一部分。我很困惑为什么notifyAll不能真正唤醒正在等待“notify 1”的另一个函数。 – micahli123 2011-04-11 14:03:18

回答

0

我不知道这是你遇到的问题,但它肯定会成为一个问题。所有对.wait()的调用都必须包含在while循环中。等待()的电话可以随机唤醒。

documentation:“作为一个参数的版本,中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:”

+0

感谢您的教学!我相信这可能是问题所在。但即使我已经纠正这个问题仍然存在。 – micahli123 2011-04-11 14:47:15

1

的原因是因为你还没有离开同步块。 read_wait方法永远不会进入if块,因为updateNotFinished默认初始化为false。由于read_wait永远不会进入if块,您将继续在finishedRead!=true上循环。在该方法和同步块被退出之前,您将永远不会放弃监视器。

一旦你完成,然后锁可用,另一个线程被正确唤醒。

要测试我在说什么,请尝试在初始化时设置updateNotFinished = true

+0

@John V.但我有updateNotFinished = true;在update_wait()中。但是,由于read()中的nofifyAll不会唤醒update_wait()中的wait(),所以updateNotFinished = true;命令不会运行,直到后期.. – micahli123 2011-04-11 14:45:01

+1

@ micahli123您看到的问题仅仅是因为read()中的线程永远不会退出。同步方法确保互斥,并且notifyAll仅在同步块中没有其他线程时唤醒线程。既然你永远不离开同步块,任何等待的线程将永远不会被唤醒,直到你退出该块。基本上,update_wait中的updateNotFinished = true永远不会被调用,直到第一个线程完成。我想你的测试 – 2011-04-11 14:47:41

+0

@约翰V.后,notify1做工作:等待 通知1 等待完成 跳过等待跳过 等待 跳过等待跳过 等待 跳过等待,但我仍然不知道为什么没有按notify1” t在我的例子中工作.. – micahli123 2011-04-11 14:51:48

0

我发现新的并发库比wait()/ notify()更容易使用这些库是有原因添加的,它们非常值得学习。这里是你的代码如何被简化的例子。

String filename = ... 
ExecutorService es = Executors.newFixedThreadPool(5); 
FileInputStream fis = new FileInputStream(filename); 

while (true) { 
    final byte[] buffer = new byte[8 * 1024]; 
    final int len = fis.read(buffer); 
    if (len < 0) break; 
    es.submit(new Runnable() { 
     public void run() { 
      process(buffer, len); 
     } 
    }); 
} 
fis.close(); 
es.shutdown(); 
es.awaitTermination(60, TimeUnit.MINUTES); 
+1

这是惊人的。我会尝试。看起来像一样。它似乎更加灵活。 – micahli123 2011-04-12 08:48:32