[英]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.