2009-11-18 77 views
27

我有一個對象阻塞隊列。java BlockingQueue沒有阻止偷看?

我想寫一個線程,直到隊列中有一個對象。類似於BlockingQueue.take()提供的功能。

但是,因爲我不知道我是否能夠成功處理對象,所以我只想偷看()而不是刪除對象。我想只在我能夠成功處理它時才移除該對象。

所以,我想要一個阻塞peek()函數。目前,如果按照javadocs排隊,peek()只會返回。

我錯過了什麼嗎?有沒有另外一種方法來實現這個功能?

編輯:

,如果我只是使用一個線程安全的隊列和偷看,睡着了,而不是有什麼想法?

public void run() { 
    while (!__exit) { 
     while (__queue.size() != 0) { 
      Object o = __queue.peek(); 
      if (o != null) { 
       if (consume(o) == true) { 
        __queue.remove(); 
       } else { 
        Thread.sleep(10000); //need to backoff (60s) and try again 
       } 
      } 
     } 
     Thread.sleep(1000); //wait 1s for object on queue 
    } 
} 

請注意,我只有一個消費者線程和一個(單獨的)生產者線程。我想這不像使用BlockingQueue那麼高效......任何意見都會被讚賞。

回答

14

你可以使用一個LinkedBlockingDeque如果處理失敗使用putLast(E e)物理(使用takeLast())隊列中刪除的項目,但在再次更換它的隊列結束。同時,您的「生產者」會使用putFirst(E e)將元素添加到隊列的前端

你總是可以封裝你自己Queue內實施這種行爲,並提供blockingPeek()方法執行之後putLast()幕後底層LinkedBlockingDequetakeLast()。因此,從調用客戶端的角度來看,元素永遠不會從您的隊列中移除。

+2

這是一個很好的建議。我在這裏可以看到的唯一問題是,如果隊列在我正在處理項目時填滿,那麼我將無法將當前項目排回。 – rouble 2009-11-18 23:56:58

+0

您可以通過在包裝器實現中使用額外的同步來解決這個問題,因此使得take + put成爲一個原子操作。你也可以使用無界隊列。 – Adamski 2009-11-19 00:09:20

+2

我建議不要刪除和重新添加,因爲那樣你就有麻煩將隊列的狀態更改暴露給其他線程。也許使用忙碌輪詢來實現peek()。或者,如果您不想輪詢,請使用綁定到包裝器隊列中的信號量。 – 2016-11-22 21:14:26

1

您是否還可以將事件偵聽器隊列添加到阻塞隊列中,然後在將某個事件添加到(阻塞)隊列時,將事件發送給偵聽器?你可以讓你的線程阻塞,直到它調用了actionPerformed方法。

0

看起來BlockingQueue的本身不具有你指定的功能被製成像BlockingQueue

雖然我可能會嘗試重新解決這個問題:您將如何處理不能「正確處理」的對象?如果你只是把他們放在隊列中,你必須在某個時候將它們拉出來並處理它們。我會推薦找出如何處理它們(通常,如果queue.get()給出任何無效或錯誤的值,那麼您可能只需將它放在地板上)或選擇不同於一個FIFO。

1

快速的回答是,並不是真的有阻止偷看的方法,而是使用阻塞窺視()自己實現阻塞隊列。

我錯過了什麼嗎?

PEEK()可能會很麻煩併發 -

  • 如果無法處理您的PEEK()'d消息 - 它會被保留在隊列,除非你有多個消費者。
  • 如果您無法處理該對象,那麼誰會將該對象從隊列中取出?
  • 如果您有多個使用者,您會在peek()'ing和另一個線程也處理項目之間獲得競爭條件,導致重複處理或更糟。

聽起來像是你可能會更好實際刪除的項目,並使用 Chain-of-responsibility pattern

編輯處理它:回覆:您的最後一個例子:如果你只有1層的消費者,你就永遠擺脫隊列中的對象 - 除非在平均時間內更新 - 在這種情況下,您最好非常小心線程安全性,並且可能不應該將項目放入隊列中。

6

但是,由於我不知道我是否能夠成功處理對象,我只想偷看()而不是刪除對象。我想只在我能夠成功處理它時才移除該對象。

一般來說,它不是線程安全的。如果在你之後peek()並確定該對象可以被成功處理,但是在你將其刪除並處理之前,另一個線程需要該對象?

+0

恕我直言,你可以通過包裝和放置一些同步來解決這個問題。邏輯 – yerlilbilgin 2016-12-30 12:33:08