我正在尝试实现一个必须满足以下要求的以插入性能为中心的,类似队列的数据结构:
我的问题是以不需要同步插入的方式获取“快照”视图。由于我可以阻止删除,并且元素只能添加到最后,因此获取元素不应成为问题。我一直遇到的问题是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)
答案 0 :(得分:3)
请勿重新发明轮子,使用ConcurrentLinkedQueue
代替LinkedList
,然后使用iterator()
构建本机线程安全的快照。
您的方法getSnapshot
将只是
public List<T> getSnapshot() {
return new ArrayList<>(queue);
}
答案 1 :(得分:0)
Java CopyOnWriteArrayList中有一个它是并发包的一部分,似乎完全符合你的要求。
但请注意,每次插入内容时它都会创建列表的副本,因此只有在您阅读的内容比您编写的内容时才应该使用它。