I have defined a ConcurrentLinkedQueue and looping over it like :
ConcurrentLinkedQueue clq .forEach((carTask -> {
Now if I delete carTask from the queue. which is an element
in the queue while we are doing a forEach will that lead to any issue ?
One alternative I think of is put the elements to be deleted
in a separate List and once the forEach is over simply delete all
the elements in the Queue from the List.
I am not sure if this alternative approach will work perfectly
Any suggestions or better way to approach this problem ?
Advertisement
Answer
This specific example won’t result in an error, because this implementation of Queue
allows concurrent modifications.
But removing elements from Java collections via the remove
method, while you’re looping over the elements, will often result in a ConcurrentModificationException
. Instead, it’s a good habit to use an Iterator
and call its remove
method:
Collection<String> c = new LinkedList<>(); c.add("foo"); c.add("bar"); for(Iterator<String> it = c.iterator(); it.hasNext(); ) { String s = it.next(); if(s.equals("foo")) { it.remove(); } } // collection now contains only "bar"
In addition to preventing ConcurrentModificationException
, this is preferable because the time complexity of remove
for many collections is linear. Since this queue is implemeneted as a linked list, the list must be traversed until the element to be removed is located. With an Iterator
, you’ve already located the element, and can remove it “in place”.
What if you locate the element you want to remove, and it’s the last element in the queue? Calling remove
on that item requires a traversal all the way to the end of the queue again. In addition, it requires a call to equals
for every preceding element. You definitely don’t want to put the items to be removed into a list, because you’d have the same negative performance characteristics (along with the allocation of another List
).