2015-04-23 24 views
3

我正在使用LinkedBlockingQueue隊列來實現producer-consumer pattern的TCP/IP事件傳輸,我使用boolean offer(e)這意味着一旦隊列達到其容量,新的傳入事件將被忽略(丟棄)和它返回false如何設置容量爲Java DelayQueue

現在我必須將事件持續一個可配置的時間(比如2秒),所以我決定使用DelayQueue,它只能在時間到期時才能保存元素和釋放元素。

不幸的是,DelayQueue無界。我想知道是否有一種方法來設置容量DelayQueuedelayQueue.size() == CAPACITY總是可靠?

+0

當隊列已滿時,是否要等到空間可用並添加到隊列中?什麼是延遲? –

+0

延遲與隊列容量無關,一個元素只能在時間到期時從隊列中取出。檢查隊列的目的是滿的是我想要統計被丟棄的事件的數量。 – haifzhan

+0

您可以在添加或子類DelayQueue以使offer()執行此操作之前檢查大小()。 –

回答

2

這是一個相當大的問題,因爲我們需要訪問使用DelayQueue如果我們要繼承它或委託給它,並且鎖是私人在DelayQueue內部鎖。

我們不能用第二個鎖定,因爲這會導致與take問題。你也許可以自己實現這一點,但是這樣做比自己實現DelayQueue還要多,所以這可能不是你想要的。

我們可以使用反射來訪問鎖。但請注意,這不是最好的想法,因爲它依賴於DelayQueue的實現細節。它可能不適用於所有的JRE,甚至可能會因爲您更改運行的JRE版本而中斷。這就是說,我認爲這是解決您的問題最簡單的方法,儘管有點骯髒。

/** 
* Bounded implementation of {@link DelayQueue}. This implementation uses 
* reflection to access the internal lock in {@link DelayQueue} so might 
* only work on the Oracle 1.8 JRE. 
* @param <T> 
*/ 
public class BoundedDelayQueue<T extends Delayed> extends DelayQueue<T> { 

    // Lock used to synchronize every operation 
    private final transient ReentrantLock lock; 

    // The limit 
    private final int limit; 

    BoundedDelayQueue(int limit) { 
     try { 
      // Grab the private lock in DelayQueue using reflection so we can use it 
      // to gain exclusive access outside of DelayQueue 
      Field lockField = DelayQueue.class.getDeclaredField("lock"); 
      lockField.setAccessible(true); 
      this.lock = (ReentrantLock) lockField.get(this); 
     } catch (NoSuchFieldException | IllegalAccessException e) { 
      throw new Error("Could not access lock field", e); 
     } 
     this.limit = limit; 
    } 

    @Override 
    // All the various ways of adding items in DelayQueue delegate to 
    // offer, so we only have to override it and not the other methods 
    public boolean offer(final T t) { 
     // Lock the lock 
     lock.lock(); 
     try { 
      // Check the size limit 
      if(size() == limit) { 
       return false; 
      } 
      // Forward to superclass 
      return super.offer(t); 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

請注意,這不以超時實現offer,如果你需要,你必須自己做。

+0

感謝您的回覆。爲什麼使用反射? BoundedDelayQueue的實例將與多線程共享,我試圖初始化BoundedDelayQueue類中的一個鎖,並在'offer(boolean)'方法中鎖定/解鎖,它是線程安全的,這裏的鎖是靜態的還是非靜態的會影響線程安全嗎?謝謝:) – haifzhan

+1

我們必須使用反射,因爲我們需要DelayQueue使用的完全相同的鎖,並且訪問它的唯一方法是通過反射。如果我們使用一個單獨的鎖,我們必須覆蓋並重新實現所有需要同步的方法 - 並且在那一點上,我們可能只是從頭開始重新實現DelayQueue,因爲這基本上就是我們要做的。 – Raniz

+0

這裏的鎖不是靜態的,它與DelayQueue使用的完全相同,因此它是線程安全的。 – Raniz