【发布时间】:2016-05-30 15:54:38
【问题描述】:
我正在尝试实现一个以插入性能为中心、类似于队列的数据结构,它必须满足以下要求:
- 必须是线程安全的
- 必须能够在不同步的情况下添加到队列
- 必须能够获得队列的“快照”视图
我的问题是以不需要同步插入的方式获取“快照”视图。由于我可以阻止删除并且元素只能添加到最后,因此获取元素应该不是问题。我一直遇到的问题是 LinkedList 的迭代器有一个不可抑制的并发修改快速失败,并且 'LinkedList.get(int)' 是 O(n)。
下面是一个简化的示例,说明我在哪里完成了一项相当简单的任务。
public class SnapshotableQueue<T> {
private final LinkedList<T> queue = new LinkedList<>();
private final Object removeLock = new Object();
public void add(T element) {
queue.add(element);
}
public T remove() {
synchronized(removeLock) {
return queue.remove();
}
}
public List<T> getSnapshot() {
synchronized(removeLock) {
int length = queue.size();
List<T> snapshot = new ArrayList<>(length);
???
return snapshot;
}
}
}
不可接受的解决方案 #1
for(int i = 0; i < length; i++)
snapshot.add(snapshot.get(i));
'LinkedList.get(int)' 是 O(n)
不可接受的解决方案 #2
Iterator<T> iterator = queue.iterator();
for(int i = 0; i < length; i++)
snapshot.add(iterator.next());
不是线程安全的(抛出 ConcurrentModificationException)
不可接受的解决方案 #3
Change queue to ArrayList
'ArrayList.remove(0)' 是 O(n)
【问题讨论】:
-
注意:你的代码不是线程安全的,你也需要一个同步块来添加方法
-
这可能是您在解决方案#2 中得到 ConcurrentModificationException 的原因
-
它实际上是线程安全的,因为我只是添加到末尾并同步删除。不幸的是,LinkedList 迭代器有一个“愚蠢的”检查来查看 anything 是否发生了变化。如果设计人员能够提供一种方法来指定您自己的迭代器,而该迭代器可能已经脱离了训练轮,那就太好了。
标签: java multithreading data-structures concurrency