2014-02-11 54 views
1

ArrayBlockingQueue,在put方法裏面,爲什麼在追上InterruptedException後調用notFull.signal()?當線程終止時,爲什麼它會發出'未滿'信號?爲什麼在捕獲InterruptedException之後ArrayBlockingQueue信號'未滿'?

source

public void put(E e) throws InterruptedException { 
     if (e == null) throw new NullPointerException(); 
     final E[] items = this.items; 
     final ReentrantLock lock = this.lock; 
     lock.lockInterruptibly(); 
     try { 
      try { 
       while (count == items.length) 
        notFull.await(); 
      } catch (InterruptedException ie) { 
       notFull.signal(); // propagate to non-interrupted thread 
       throw ie; 
      } 
      insert(e); 
     } finally { 
      lock.unlock(); 
     } 
    } 
+0

請注意,自打開JDK的[Java 7實現]以來,我使用Java 6進行了標記(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/util /concurrent/ArrayBlockingQueue.java#ArrayBlockingQueue.put%28java.lang.Object%29)似乎已經改變。 –

回答

1

試想以下情形:

  • 線程1和4正在等待notFull,隊列已滿,鎖被釋放。
  • 線程2擁有鎖,並且即將從隊列中移除一個元素。
  • 線程3中斷線程1

現在想象一下以下的交織:

+-+--+--------+-----------+------- TIME +---+------------+----------------------> 
| | |  |   |    | |   | 
+---------+ +------------------+  +----------+  | 
| Thread2 | |  Thread2  |  | Thread2 |  | 
| lock() | | notFull.signal() |  | unlock() |  | 
+---------+ +------------------+  +----------+  | 
    | |     |     |   | 
    +---------------------+ |     |   | 
    |  Thread3  | |     |   | 
    | Thread1.interrupt() | |     |   | 
    +---------------------+ |     |   | 
    |     |     |   | 
    +---------------+ +-------------+ +---------+ +----------------------+ 
    | Thread1  | | Thread1 | | Thread1 | |  Thread1  | 
    | interrupted() | | signalled() | | lock() | | InterruptedException | 
    +---------------+ +-------------+ +---------+ +----------------------+ 

如果InterruptedException沒有抓住什麼,線程1只是解鎖,放棄等待?線程4會發生什麼,他仍然在等待notFull上的信號?該信號已經由線程2發送,但恰好接收線程Thread 1被中斷,並且信號浪費了

簡而言之:如果線程在中斷的時候收到了一個信號,它就將信號傳遞給另一個線程,這樣它就不會丟失。這可以防止線程無限期地等待已經發生的事情。

+0

+1很好的解釋和圖表。您是否介意評論與Java 7版本(在我上面的評論中鏈接)的差異?我試圖看看它有什麼不同,爲什麼它會改變。 –

+1

@Paul Bellora:我不知道它是否真的有必要,但通過查看「WaitQueuedSynchronizer.ConditionObject」的Java 7代碼,它是「wait」功能的後端,它變得很清楚,它不是這個實現是必需的。消費信號並接收「InterruptedException」是互斥的。所以沒有必要捕捉異常並重新發送信號。 – Holger

+0

@PaulBellora正如@Holger所說,查看「AbstractQueuedSynchronizer.ConditionObject」的Java 7代碼告訴我們,resignalling不再是必需的。任何線程中斷之前,信號都不會發出信號。 Java 6中的代碼是不同的,所以它*可能是必需的。雖然,重要的部分(doSignal方法)保持不變。 – afsantos

相關問題