2014-11-06 116 views
2

我正在閱讀Java LinkedBlockingQueue源代碼,我有兩個關於put operation的問題。Java LinkedBlockingQueue源代碼混淆

public void put(E e) throws InterruptedException { 
    if (e == null) throw new NullPointerException(); 
    // Note: convention in all put/take/etc is to preset local var 
    // holding count negative to indicate failure unless set. 
    int c = -1; 
    Node<E> node = new Node<E>(e); 
    final ReentrantLock putLock = this.putLock; 
    final AtomicInteger count = this.count; 
    putLock.lockInterruptibly(); 
    try { 
     /* 
     * Note that count is used in wait guard even though it is 
     * not protected by lock. This works because count can 
     * only decrease at this point (all other puts are shut 
     * out by lock), and we (or some other waiting put) are 
     * signalled if it ever changes from capacity. Similarly 
     * for all other uses of count in other wait guards. 
     */ 
     while (count.get() == capacity) { 
      notFull.await(); 
     } 
     enqueue(node); 
     c = count.getAndIncrement(); 
     if (c + 1 < capacity) 
      notFull.signal(); 
    } finally { 
     putLock.unlock(); 
    } 
    if (c == 0) 
     signalNotEmpty(); 
} 

我不明白:

  1. 它檢查c + 1 < capacity,當它發出notFull.signal()。爲什麼不使用c < capacity
  2. 爲什麼當c == 0在函數結束時發出signalNotEmpty

另外,我也不明白爲什麼頭部/尾部需要是transient

+0

Java 6真的是你感興趣的版本嗎? – 2014-11-06 05:36:25

+0

@Tichodroma這個方法在Java 7或8中幾乎沒有變化。我將添加Java 8的代碼。 – 2014-11-06 05:49:25

+1

OP,我已經添加了Java 8的相關源代碼。我可以更改鏈接到Java 8版本呢? – 2014-11-06 05:53:37

回答

4

到你的兩個問題的答案:

  1. c + 1 < capacity檢查之前,對c = count.getAndIncrement();通話。由於計數遞增後它檢索並分配給c,還有的c和實際計數,因此,在檢查的+ 1之間的差。
  2. 只有在隊列由空變爲非空時才需要發送非空信號。只有當第一個元素被添加到一個空的(0元素)隊列時纔是這種情況。至於c在這一點上是而不是,請參閱第一個問題的答案。

關於headtailtransient:他們不需要在對象序列化是持久的,因爲他們是通過在反序列化對象的默認構造函數初始化。

+1

謝謝,現在我明白了getAndIncrement()的技巧。頭部/尾部在缺省構造函數中指向具有空值的節點。這是否意味着如果我們序列化/反序列化阻塞隊列,我們​​會丟失阻塞隊列中的內容? – GarudaReiga 2014-11-06 06:32:29

+0

在這個實現中,'head'總是一個空節點。你不會失去任何東西。 – 2014-11-06 06:50:54