假设我有ConcurrentLinkedQueue
类型的类字段。此类的一些方法是向此队列提供新元素。其他一些方法需要在这个确切的时刻轮询队列内的所有元素。
我无法在循环中使用poll()
,因为在循环仍未完成时,有可能会向此队列提供某些元素。如果新元素的提供速度比我调查的速度快,我认为它甚至可以是无限循环。所以我需要某种pollAll()
。
有没有办法实现这个目标?也许有一个适合这个的集合?
答案 0 :(得分:3)
如果您可以更改应用程序以使用其中一个BlockingQueue
实现,那么有一种方法drainTo
似乎可以完全按照您的要求执行。它会删除队列的当前内容并将它们传输到目标集合。
有各种BlockingQueue
实现;它们都应该是线程安全的。奇怪的是,没有指定drainTo
是原子的,尽管它在我检查的实现中(ArrayBlockingQueue
和LinkedBlockingQueue
)。
答案 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)。