2011-04-11 67 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