2011-03-08 30 views

回答

0

您可以覆盖任何实施BlockingQueue<T>的add和put方法,以首先检查元素是否已经在队列中,例如,

@Override 
public boolean add(T elem) { 
    if (contains(elem)) 
     return true; 
    return super.add(elem); 
} 
+0

好的,但不是最优的,因为正常的BlockingQueue实现包含的()要求整个队列 – 2011-03-08 19:56:48

+0

的遍历,我会说:“最佳”是主观的。除非你自己推出,否则其他简单的选项就是秒杀建议的选项,这是一个经典的空间与时间的折衷。所以虽然任何一个都可以被认为是最好的解决方案,但依靠它的用途,我会因为它的简单性而投票赞成。 – 2011-03-08 21:03:27

+7

如果“最优”包含正确的,那么这个实现会失败,因为它是一个竞争条件。 – jtahlborn 2012-11-21 15:57:37

4

您可以创建一个组成BlockingQueue,Set和锁的新类。当你把()你测试对照集合,同时拿着防止get()运行的锁。当你得到()时,你从该集合中删除该项目,以便它可以在将来再次放置()。

-2
class BlockingSet extends ArrayBlockingQueue<E> { 
    /*Retain all other methods except put*/ 
    public void put(E o) throws InterruptedException { 
     if (!this.contains(o)){ 
     super.put(o); 
     } 
    } 
} 
+0

'contains'的实现遍历列表,这会很慢... – 2013-04-12 13:23:48

1

通过用于预知迭代顺序和一定的时间增加,删除和链接哈希set支持一种阻塞队列实现包含操作:

There you go

+0

感觉非常慢。 – horec 2015-12-14 10:09:29

+0

@horec - 这种感觉来自于看代码还是来自实际尝试呢?看着他的代码,我有同样的担忧,但还没有真正给它一杆尚未 – forhas 2016-01-05 08:48:19

+0

您的链接已经死了:-( – rcomblen 2017-05-30 09:55:59

1

我写了这个类来解决类似的问题:

/** 
* Linked blocking queue with {@link #add(Object)} method, which adds only element, that is not already in the queue. 
*/ 
public class SetBlockingQueue<T> extends LinkedBlockingQueue<T> { 

    private Set<T> set = Collections.newSetFromMap(new ConcurrentHashMap<>()); 

    /** 
    * Add only element, that is not already enqueued. 
    * The method is synchronized, so that the duplicate elements can't get in during race condition. 
    * @param t object to put in 
    * @return true, if the queue was changed, false otherwise 
    */ 
    @Override 
    public synchronized boolean add(T t) { 
     if (set.contains(t)) { 
      return false; 
     } else { 
      set.add(t); 
      return super.add(t); 
     } 
    } 

    /** 
    * Takes the element from the queue. 
    * Note that no synchronization with {@link #add(Object)} is here, as we don't care about the element staying in the set longer needed. 
    * @return taken element 
    * @throws InterruptedException 
    */ 
    @Override 
    public T take() throws InterruptedException { 
     T t = super.take(); 
     set.remove(t); 
     return t; 
    } 
}