1

I am trying to implement an insertion-performance-focused, queue-like data structure that must meet the following requirements:

  1. Must be thread-safe
  2. Must be able to add to queue without synchronizing
  3. Must be able to get a "snapshot" view of the queue

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)

3
  • NB: your code is not thread safe, you need a synchronized block for the method add too Commented May 30, 2016 at 16:02
  • this is probably the reason why you get the ConcurrentModificationException in solution #2 Commented May 30, 2016 at 16:04
  • It actually is thread safe since I am only adding to the end and am synchronizing the remove. Unfortunately, the LinkedList iterator has a "dumb" check for seeing if anything changes. It would have been nice for the designers to provide a way to specify your own iterator that could have left off the training wheels. Commented May 30, 2016 at 22:18

2 Answers 2

3

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);
}
Sign up to request clarification or add additional context in comments.

4 Comments

I'd recommend that too. It uses an algorithm with separate write and read locks based on cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf The link in the javadoc to that document on michaels user space is outdated X) It should provide thread safe and concurrent read and write access with high performance.
Awesome. I had looked briefly at this when scanning the "java.util.concurrent" package, but for some reason I ended up passing over it. Looked closer at the JavaDocs and a benchmarking blog javacodegeeks.com/2010/09/… Looks great. Thanks for pointing me back the right way.
@doge this is a different story but if T is not thread safe and it is read and modify by several threads concurrently you will face indeed issues
This is what I am talking about. If class is not completely thread-safe it is not thread-safe. This issue must be considered too. Sharing not-thread-safe state can be achieved by deep-copy.
0

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.

2 Comments

I will be writing way more than reading, so this will not work for me. Thanks anyway.
yes that's right CopyOnWriteArrayList is only interesting when you mostly read and rarely write otherwise it is a perf killer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.