簡體   English   中英

有界優先阻塞隊列

[英]Bounded PriorityBlockingQueue

PriorityBlockingQueue是無界的,但我需要以某種方式對其進行綁定。 實現這一目標的最佳方法是什么?

有關信息,有界PriorityBlockingQueue將在ThreadPoolExecutor

注意:如果發生這種情況,我不想拋出異常,我想將對象放入隊列中,然后根據其優先級值剪切它。 有沒有什么好方法可以做到這一點?

我實際上不會對它進行子類化。 雖然我現在無法將示例代碼放在一起,但我建議使用裝飾器模式的一個版本。

創建一個新類並實現您感興趣的類實現的接口: PriorityBlockingQueue 我發現這個類使用了以下接口:

Serializable, Iterable<E>, Collection<E>, BlockingQueue<E>, Queue<E>

在類的構造函數中,接受PriorityBlockingQueue作為構造函數參數。

然后通過PriorityblockingQueue的實例實現接口所需的所有方法。 添加使其有界所需的任何代碼。 這是裝飾者模式的一個相當標准的實現。

Google Collections/Guava庫中有一個實現: MinMaxPriorityQueue

min-max 優先級隊列可以配置為最大大小。 如果是這樣,每次隊列的大小超過該值時,隊列會根據其比較器(可能是剛剛添加的元素)自動刪除其最大元素。 這與傳統的有界隊列不同,后者在滿時阻塞或拒絕新元素。

在我的頭頂上,我會將它子類化並覆蓋 put 方法以強制執行此操作。 如果它超過拋出異常或做任何看起來合適的事情。

就像是:

public class LimitedPBQ extends PriorityBlockingQueue {

    private int maxItems;
    public LimitedPBQ(int maxItems){
        this.maxItems = maxItems;
    }

    @Override
    public boolean offer(Object e) {
        boolean success = super.offer(e);
        if(!success){
            return false;
        } else if (this.size()>maxItems){
            // Need to drop last item in queue
            // The array is not guaranteed to be in order, 
            // so you should sort it to be sure, even though Sun's Java 6 
            // version will return it in order
            this.remove(this.toArray()[this.size()-1]);
        }
        return true;
    }
}

編輯:添加和放置調用報價,因此覆蓋它應該就足夠了

編輯 2:如果超過 maxItems,現在應該刪除最后一個元素。 不過,可能有一種更優雅的方式來做到這一點。

根據 Frank V 的建議實現了 BoundedPriorityBlockingQueue 后,我意識到它並沒有達到我想要的效果。 主要問題是我必須插入隊列的項目可能比隊列中已有的所有項目具有更高的優先級。 因此,我真正想要的是一個“樞軸”方法,如果我將一個對象放入隊列中,當隊列已滿時,我想取回優先級最低的對象,而不是阻塞。

為了充實 Frank V 的建議,我使用了以下片段......

public class BoundedPriorityBlockingQueue<E> 
   implements 
     Serializable, 
     Iterable<E>, 
     Collection<E>, 
     BlockingQueue<E>, 
     Queue<E>, 
     InstrumentedQueue 
{

... 私有最終 ReentrantLock 鎖; // = 新的 ReentrantLock(); 私人最終條件 notFull;

final private int capacity;
final private PriorityBlockingQueue<E> queue;

public BoundedPriorityBlockingQueue(int capacity) 
  throws IllegalArgumentException, 
         NoSuchFieldException, 
         IllegalAccessException 
{
   if (capacity < 1) throw 
       new IllegalArgumentException("capacity must be greater than zero");      
   this.capacity = capacity;
   this.queue = new PriorityBlockingQueue<E>();

   // gaining access to private field
   Field reqField;
   try {
    reqField = PriorityBlockingQueue.class.getDeclaredField("lock");
    reqField.setAccessible(true);
    this.lock = (ReentrantLock)reqField.get(ReentrantLock.class);
    this.notFull = this.lock.newCondition();

   } catch (SecurityException ex) {
    ex.printStackTrace();
    throw ex;
   } catch (NoSuchFieldException ex) {
    ex.printStackTrace();
    throw ex;
   } catch (IllegalAccessException ex) {
    ex.printStackTrace();
    throw ex;
   }

...

@Override
public boolean offer(E e) {
    this.lock.lock();
    try {
        while (this.size() == this.capacity)
            notFull.await();
        boolean success = this.queue.offer(e);
        return success;
    } catch (InterruptedException ie) {
        notFull.signal(); // propagate to a non-interrupted thread
        return false;

    } finally {
        this.lock.unlock();
    }
}
...

這也有一些工具,所以我可以檢查隊列的有效性。 我仍在研究“PivotPriorityBlockingQueue”,如果有人感興趣,我可以發布它。

ConcurrencyUtils repo 中有一個實現。

如果您要執行的 Runnables 的順序不嚴格(原樣:即使存在較高優先級的任務,也可能會執行一些較低優先級的任務),那么我建議以下,歸結為定期切割 PriorityQueue縮小尺寸:

if (queue.size() > MIN_RETAIN * 2){
    ArrayList<T> toRetain = new ArrayList<T>(MIN_RETAIN);
    queue.drainTo(toRetain, MIN_RETAIN);
    queue.clear();
    for (T t : toRetain){
      queue.offer(t);
    }
}

如果順序需要嚴格,這顯然會失敗,因為排空會導致一個時刻,wenn 低優先級任務將使用並發訪問從隊列中檢索。

優點是,這是線程安全的,並且可能與優先級隊列設計一樣快。

到目前為止,沒有一個答案具有以下所有屬性:

  • 實現BlockingQueue接口。
  • 支持去除絕對最大值。
  • 沒有比賽條件。

不幸的是,標准 Java 庫中沒有BlockingQueue實現。 你要么需要找到一個實現,要么自己實現一些東西。 實現BlockingQueue需要一些有關正確鎖定的知識。

這是我的建議:查看https://gist.github.com/JensRantil/30f812dd237039257a3d並將其用作模板來實現您自己的SortedSet包裝器。 基本上,所有鎖定都在那里,並且有多個單元測試(需要一些調整)。

還有另一種實現在這里

它似乎可以滿足您的要求:

BoundedPriorityQueue 實現了一個具有元素數量上限的優先級隊列。 如果隊列未滿,則始終添加添加的元素。 如果隊列已滿並且添加的元素大於隊列中的最小元素,則移除最小元素並添加新元素。 如果隊列已滿且添加的元素不大於隊列中的最小元素,則不添加新元素。

查看來自 Google Collections API 的ForwardingQueue 對於阻塞語義,您可以使用Semaphore

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM