Java - ConcurrentLinkedQueue - 全部轮询

时间:2016-01-08 12:57:25

标签: java collections

假设我有ConcurrentLinkedQueue类型的类字段。此类的一些方法是向此队列提供新元素。其他一些方法需要在这个确切的时刻轮询队列内的所有元素

我无法在循环中使用poll(),因为在循环仍未完成时,有可能会向此队列提供某些元素。如果新元素的提供速度比我调查的速度快,我认为它甚至可以是无限循环。所以我需要某种pollAll()

有没有办法实现这个目标?也许有一个适合这个的集合?

2 个答案:

答案 0 :(得分:3)

如果您可以更改应用程序以使用其中一个BlockingQueue实现,那么有一种方法drainTo似乎可以完全按照您的要求执行。它会删除队列的当前内容并将它们传输到目标集合。

有各种BlockingQueue实现;它们都应该是线程安全的。奇怪的是,没有指定drainTo是原子的,尽管它在我检查的实现中(ArrayBlockingQueueLinkedBlockingQueue)。

答案 1 :(得分:1)

好像你需要某种"暂停"时刻。一种做法:

    AbstractQueue<Object> queue = new ConcurrentLinkedQueue<>();
    int size = queue.size();

    for (int i = 0; i < size; i++) {
        Object object = queue.poll();
        if (object == null) {
            // Collection has shronk break
            break;
        }
        // Do processing here
    } 

通过将大小存储到局部变量中,大小不会改变,您可以使用该数量的元素进行处理。如果在添加过程元素期间,它将无法受到无限循环的影响。

更新:使用.iterator()可能比我的第一个例子更好:

  

返回的迭代器是一个&#34;弱一致的&#34;将要的迭代器   永远不会抛出ConcurrentModificationException ,并保证   在构造迭代器时存在的遍历元素,   并且可能(但不保证)反映任何修改   在施工之后。

更新2 :这是将所有元素也删除一次并处理它的方法。

        AbstractQueue<Object> queue = new ConcurrentLinkedQueue<>();
        queue.add("Test1");
        queue.add("Test2");
        queue.add("Test3");

        Object[] objList = queue.toArray();

        queue.remove("Test2");

        for (Object obj : objList) {
            // Make sure you delete it, because we don't use .poll
            // Put it at top, to reproduce the poll as much as possible
            queue.remove(obj);

            // Do processing
        }

这将输出:

Test1
Test2
Test3 

由于复制到新objList[],它还会显示&#34; Test2&#34;。如果将重复项添加到列表中,此示例可能会导致.remove()方法出现问题。因为if和element被添加到.remove()中的对象,所以该对象立即被删除。

另请注意,此方法较慢,因为.remove()需要遍历元素才能找到它O(N1),其中.poll是即时O(1)。