【问题标题】:Java blocking queue containing only unique elements仅包含唯一元素的 Java 阻塞队列
【发布时间】:2011-07-11 08:55:51
【问题描述】:

有点像“阻塞集”。如何实现阻塞队列,忽略添加已在集合中的成员?

【问题讨论】:

    标签: java queue


    【解决方案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;
        }
    }
    

    【讨论】:

    • 如果我们关心从队列和集合中原子地删除元素怎么办?
    【解决方案2】:

    您可以创建一个由 BlockingQueue、Set 和锁组成的新类。当您 put() 时,您会在持有阻止 get() 运行的锁的同时对集合进行测试。当您 get() 时,您从集合中删除该项目,以便将来可以再次 put()。

    【讨论】:

      【解决方案3】:

      由链接哈希集支持的阻塞队列实现,用于可预测的迭代顺序和恒定时间添加、删除和包含操作:

      There you go.

      【讨论】:

      • @horec - 这种感觉是来自查看代码还是来自实际尝试?查看代码我也有同样的担忧,但还没有真正尝试过
      • 您的链接已失效 :-(
      • @romblen - 已修复。
      • @forhas 你的链接又失效了。
      【解决方案4】:

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

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

      【讨论】:

      • 很好但不是最优的,因为 contains() 的普通 BlockingQueue 实现需要遍历整个队列
      • 我会说“最佳”是主观的。除非您自己动手,否则另一个简单的选项是 Speak 建议的选项,这是经典的空间与时间权衡。因此,尽管根据使用情况,两者都可以被认为是最佳解决方案,但由于其简单性,我对此投了赞成票。
      • 如果“最佳”包括正确的,那么这个实现将失败,因为它是一个竞争条件。
      【解决方案5】:
      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);
            }
         }
      }
      

      【讨论】:

      • contains的实现会遍历列表,这样会很慢...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      相关资源
      最近更新 更多