In principle it is easy to remove an element from ConcurrentLinkedQueue or similar implementation. For example, the Iterator
for that class supports efficient O(1) removal of the current element:
public void remove() {
Node<E> l = lastRet;
if (l == null) throw new IllegalStateException();
// rely on a future traversal to relink.
l.item = null;
lastRet = null;
}
I want to add an element to the queue with add()
, and then later delete that exact element from the queue. The only options I can see are:
Save a reference to the object and call
ConcurrentLinkedQueue.remove(Object o)
with the object - but this forces a traversal of the whole queue in the worst case (and half on average with a random add and removal pattern).This has the further issue that it doesn't necessarily remove the same object I inserted. It removes an equal object, which may very be a different one if multiple objects in my queue are equal.
Use
ConcurrentLinkedDeque
instead, thenaddLast()
my element, then immediately grab adescendingIterator()
and iterate until I find my element (which will often be the first one, but may be later since I'm effectively swimming against the tide of concurrent additions).This addition to being awkward and potentially quite slow, this forces me to use
Deque
class which in this case is much more complex and slower for many operations (check outIterator.remove()
for that class!).Furthermore this solution still has a subtle failure mode if identical (i.e.,
==
identity) can be inserted, because I might find the object inserted by someone else, but that can ignored in the usual case that is not possible.
Both solutions seem really awkward, but deleting an arbitrary element in these kind of structures seems like a core operation. What am I missing?
It occurs to me this is a general issue with other concurrent lists and dequeues and even with non concurrent structures like LinkedList
.
C++ offers it in the form of methods like insert.