Reputation: 2996
I am trying to implement an insertion-performance-focused, queue-like data structure that must meet the following requirements:
My issue is getting the 'snapshot' view in a way that doesn't require synchronization of the insert. Since I can block the removal and elements can only be added to the end, getting the elements shouldn't be an issue. The problem I keep running into is that the LinkedList's iterator has an unsupressable concurrent modification fast-fail baked in and 'LinkedList.get(int)' is O(n).
Below is a pared-down example of where I am with what should be a fairly simple task.
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;
}
}
}
Unacceptable Solution #1
for(int i = 0; i < length; i++)
snapshot.add(snapshot.get(i));
'LinkedList.get(int)' is O(n)
Unacceptable Solution #2
Iterator<T> iterator = queue.iterator();
for(int i = 0; i < length; i++)
snapshot.add(iterator.next());
Isn't thread-safe (throws ConcurrentModificationException)
Unacceptable Solution #3
Change queue to ArrayList
'ArrayList.remove(0)' is O(n)
Upvotes: 1
Views: 104
Reputation: 44965
Don't reinvent the wheel, use ConcurrentLinkedQueue
instead of LinkedList
then use the iterator()
to build your snapshot which is natively thread safe.
Your method getSnapshot
will then be simply
public List<T> getSnapshot() {
return new ArrayList<>(queue);
}
Upvotes: 3
Reputation: 115
There is this one in Java CopyOnWriteArrayList it's part of the concurrent package and seems to do exactly what you want.
But mind that it creates a copy of the list every time you insert something, so it should only be used in scenarios were you read a lot more than you write.
Upvotes: 0