Remove while iterating leaves element and does not throw Concurrent E - java

I encountered this piece a of code, that removes item from list while iterating, and yet it does not throw concurrent exception and leaves some items in the list.
Why is that?
Example:.
public class Application {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
for (Integer integer : integerList) {
removeInteger(integerList, integer);
}
System.out.println(integerList.toString()); // prints [2] as it was not removed (while it should be)
}
private static void removeInteger(List<Integer> integerList, Integer integer) {
for (Integer integer1 : integerList) {
if (integer.equals(integer1)) {
int index = integerList.indexOf(integer);
if (index >= 0) {
integerList.remove(index);
}
}
}
}
}
If I change removeInteger method to use Iterator instead and in main I pass a copy of integerList everything works as expected.

First of all if you add some more elements to the list it will still fail with a ConcurrentModificationException.
For the reason that it does not fail with the posted example, we have to take a look at what happens internally.
If you debug you see that in the posted example, both loops are only iterated once. Removing the element in the inner loop (removeInteger method) exhausts both iterators. As there is no further interaction, no error is caused. 'Only' a call of Iterator#next after a modification could cause a ConcurrentModificationException.
Yes, but why does it exhaust them?
Checking the source code of ArrayList#Itr we can see that
public boolean hasNext() {
return cursor != size;
}
only checks a variable called size. This variable size is a property of the ArrayList. When remove is called this variable is decremented. Hence the next time hasNext is called, the Iterator assumes there are no more new elements.
SideNote: cursor points at the next element in the list.

Related

Why ConcurentModificationException isn't always thrown when we remove element in a for loop [duplicate]

This question already has an answer here:
ConcurrentModificationException not thrown consistently
(1 answer)
Closed 1 year ago.
G'day everyone. Today I get a quite weird situations regarding ConcurentModificationException.
I have a list like this.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
I also have three pieces of code like this.
This will print [2, 3].
for (int i = 0; i < list.size(); i++) {
Integer integer = list.get(i);
if (integer.equals(1)) {
list.remove(integer);
}
}
System.out.println(list);
This will throw exception.
for (Integer integer : list) {
if (integer.equals(1)) {
list.remove(integer);
}
}
System.out.println(list);
This will print [1, 3].
for (Integer integer : list) {
if (integer.equals(2)) {
list.remove(integer);
}
}
System.out.println(list);
I used to think that removing an element inside a for-loop always results ConcurrentModificationException but I might be wrong. Can you guys tell me what create the difference here.
I run the code on Corretto 11.
The point here is that the ConcurrentModificationException is thrown when you access(!) the next element via the iterator, not when checking for the existance of a further element.
In the second snippet you remove the first element then there are still two to go. For the next iteration it will be noticed, that there are more elements which will be accessed and as the expectedModCount changed, the Exception will be thrown.
In the third example however, due to the reduced size, you will have reached the end after the second iteration and no further access will take place and therefore no exception is thrown.
The first example is not meant to throw an exception, because you are not using an iterator, which would check for the concurrent modification in the first place.
As was mentioned earlier first code snippet is not supposed to throw ConcurrentModificationException, because you are not iterating over list.
As regards to other two snippets the equivalent code is following:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
Iterator it = list.iterator();
while(it.hasNext()) {
Integer integer = (Integer)it.next();
if (integer.equals(2)) {
list.remove(integer);
}
}
System.out.println(list);
and if you take a look at java.util.ArrayList.Itr implementation:
public boolean hasNext() {
return cursor != size;
}
#SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
you can find out that the reason of such behaviour is caused by cursor = i + 1 in next() call: removing penultimate element in ArrayList decreases size and followed hasNext() call returns false.
A regular for loop and an enhanced one are, slightly, different.
While the regular one loops over the list and gets the individual elements one by one, the enhanced one uses an Iterator. The enhanced for loop works with Iterable objects or an array.
Basically the enhanced for loop translates to this
for(Iterator<Integer> it = list.iterator(); it.hasNext(); ) {
Integer integer = it.next();
if (integer.equals(2)) {
list.remove(integer);
}
}
This also explains why the first enhanced loop throws an exception. As according to the iterator there should be more elements. Calling the next method detects that the underlying collection has changed and thus throws a ConcurrentModificationException.
The last one doesn't because you are already at the end of the iterator and thus no additional call to next.
When you remove an element at index 0, the list shrinks, therefore your list with [1,2,3] is now [2,3]. you then remove index 1 wich remove the 3. You have now [2] in your list. Then you remove index 2 which no longer exist.
You may want to remove only index 0 at every iteration or remove from the last index to the first.

List does not throws an exception while removing an element from the list while iterating [duplicate]

Note: I am aware of the Iterator#remove() method.
In the following code sample, I don't understand why the List.remove in main method throws ConcurrentModificationException, but not in the remove method.
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer toRemove) {
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer toRemove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
}
Here's why:
As it is says in the Javadoc:
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
This check is done in the next() method of the iterator (as you can see by the stacktrace). But we will reach the next() method only if hasNext() delivered true, which is what is called by the for each to check if the boundary is met. In your remove method, when hasNext() checks if it needs to return another element, it will see that it returned two elements, and now after one element was removed the list only contains two elements. So all is peachy and we are done with iterating. The check for concurrent modifications does not occur, as this is done in the next() method which is never called.
Next we get to the second loop. After we remove the second number the hasNext method will check again if can return more values. It has returned two values already, but the list now only contains one. But the code here is:
public boolean hasNext() {
return cursor != size();
}
1 != 2, so we continue to the next() method, which now realizes that someone has been messing with the list and fires the exception.
Hope that clears your question up.
Summary
List.remove() will not throw ConcurrentModificationException when it removes the second last element from the list.
One way to handle it it to remove something from a copy of a Collection (not Collection itself), if applicable. Clone the original collection it to make a copy via a Constructor.
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For your specific case, first off, i don't think final is a way to go considering you intend to modify the list past declaration
private static final List<Integer> integerList;
Also consider modifying a copy instead of the original list.
List<Integer> copy = new ArrayList<Integer>(integerList);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
copy.remove(integer);
}
}
The forward/iterator method does not work when removing items. You can remove the element without error, but you will get a runtime error when you try to access removed items. You can't use the iterator because as pushy shows it will cause a ConcurrentModificationException, so use a regular for loop instead, but step backwards through it.
List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
int size= integerList.size();
//Item to remove
Integer remove = Integer.valueOf(3);
A solution:
Traverse the array in reverse order if you are going to remove a list element. Simply by going backwards through the list you avoid visiting an item that has been removed, which removes the exception.
//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
if (integerList.get(i).equals(remove) ) {
integerList.remove(i);
}
}
This snippet will always throw a ConcurrentModificationException.
The rule is "You may not modify (add or remove elements from the list) while iterating over it using an Iterator (which happens when you use a for-each loop)".
JavaDocs:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.
Hence if you want to modify the list (or any collection in general), use iterator, because then it is aware of the modifications and hence those will be handled properly.
Hope this helps.
I had that same problem but in case that I was adding en element into iterated list.
I made it this way
public static void remove(Integer remove) {
for(int i=0; i<integerList.size(); i++) {
//here is maybe fine to deal with integerList.get(i)==null
if(integerList.get(i).equals(remove)) {
integerList.remove(i);
}
}
}
Now everything goes fine because you don't create any iterator over your list, you iterate over it "manually". And condition i < integerList.size() will never fool you because when you remove/add something into List size of the List decrement/increment..
Hope it helps, for me that was solution.
If you use copy-on-write collections it will work; however when you use list.iterator(), the returned Iterator will always reference the collection of elements as it was when ( as below )
list.iterator() was called, even if another thread modifies the collection. Any
mutating methods called on a copy-on-write–based Iterator or ListIterator
(such as add, set, or remove) will throw an UnsupportedOperationException.
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new CopyOnWriteArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
This runs fine on Java 1.6
~ % javac RemoveListElementDemo.java
~ % java RemoveListElementDemo
~ % cat RemoveListElementDemo.java
import java.util.*;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
~ %
In my case I did it like this:
int cursor = 0;
do {
if (integer.equals(remove))
integerList.remove(cursor);
else cursor++;
} while (cursor != integerList.size());
Change Iterator for each into for loop to solve.
And the Reason is:
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
--Referred Java Docs.
Check your code man....
In the main method you are trying to remove the 4th element which is not there and hence the error.
In the remove() method you are trying to remove the 3rd element which is there and hence no error.

Understanding concurrentModificationException and implementation of ArrayList

I tried to reproduce ConcurrentModificationException myself by writing the following code:
List<String> last = new ArrayList<>();
last.add("a");
last.add("b");
for(String i : last){
System.out.println(i);
last.remove(i);
}
System.out.println(last);
DEMO
Since, the documentation of ArrayList mentioned
Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees
in the presence of unsynchronized concurrent modification.
I expected that in single-threaded programs such detection is straghtforward. But the program printed
a
[b]
instead. Why?
Your code is equivalent to the following:
List<String> last = new ArrayList<>();
last.add("a");
last.add("b");
for(Iterator<String> i = last.iterator(); i.hasNext(); ) {
String value = i.next();
System.out.println(value);
last.remove(value);
}
System.out.println(last);
The flow of the for loop is:
System.out.println(value); // prints "a"
last.remove(value); // removes "a" from the list
i.hasNext() // exits the loop, since i.hasNext() is false
System.out.println(last); // prints "[b]" - the updated list
That's why you get your output and no ConcurrentModificationException.
You will get ConcurrentModificationException if you'll add another value to your list (e.g. last.add("c")), because then i.hasNext() will be true after the first iteration and i.next() will throw the exception.
As explained in the documentation:
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException
Because you are looping through the list using the new syntax for(String i : last) an iterator is created for you and you can't modify the list while looping it.
This exception is not related to multithreading. Also working with only one thread you can throw that exception.
Internally there is a variable modCount that is incremented for every modification to the structure of the list. When the iterator is first created it saves that value of modCount in a variable expectedModCount. Every subsequent modification check if that value of expectedModCount is equal to modCount. If not a ConcurrentModificationException is thrown.
I add the code of remove as an example. The same for add, addAll and all others methods that modify the list.
public E remove(int index) {
rangeCheck(index);
// Check if a modification should thrown a ConcurrentModificationException
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
final void checkForComodification() {
if (expectedModCount != ArrayList.this.modCount)
throw new ConcurrentModificationException();
}
}
Itr class in ArrayList class has following methods
public boolean hasNext() {
return cursor != size;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Here, modCount is the number of times list has been structurally modified. When we create for loop, internally an iterator will be created and expectedModCount will be initialized to modCount.
When there are only 2 elements in the list and after removing one element, for loop will check the condition using hasNext() method call. So, condition cursor != size (1!=1) will be met first. Hence, loop won't proceed further and ConcurrentModificationException will not be thrown.
But, when there are 1,3,4 etc number of elements are there in the list then, for loop will proceed further after hasNext() method call. But, while fetching the element using next() method inside for loop, it will call checkForComodification() and condition modCount != expectedModCount will be met. Hence, exception will be thrown.
For two values, it will not fail because the for loop will be exited. Add a third element and you will get java.util.ConcurrentModificationException
List<String> last = new ArrayList<>();
last.add("a");
last.add("b");
last.add("c");
for(String i : last){
System.out.println(i);
last.remove(i);
}
System.out.println(last);

Why am I not getting a java.util.ConcurrentModificationException in this example?

Note: I am aware of the Iterator#remove() method.
In the following code sample, I don't understand why the List.remove in main method throws ConcurrentModificationException, but not in the remove method.
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer toRemove) {
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer toRemove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
}
Here's why:
As it is says in the Javadoc:
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
This check is done in the next() method of the iterator (as you can see by the stacktrace). But we will reach the next() method only if hasNext() delivered true, which is what is called by the for each to check if the boundary is met. In your remove method, when hasNext() checks if it needs to return another element, it will see that it returned two elements, and now after one element was removed the list only contains two elements. So all is peachy and we are done with iterating. The check for concurrent modifications does not occur, as this is done in the next() method which is never called.
Next we get to the second loop. After we remove the second number the hasNext method will check again if can return more values. It has returned two values already, but the list now only contains one. But the code here is:
public boolean hasNext() {
return cursor != size();
}
1 != 2, so we continue to the next() method, which now realizes that someone has been messing with the list and fires the exception.
Hope that clears your question up.
Summary
List.remove() will not throw ConcurrentModificationException when it removes the second last element from the list.
One way to handle it it to remove something from a copy of a Collection (not Collection itself), if applicable. Clone the original collection it to make a copy via a Constructor.
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For your specific case, first off, i don't think final is a way to go considering you intend to modify the list past declaration
private static final List<Integer> integerList;
Also consider modifying a copy instead of the original list.
List<Integer> copy = new ArrayList<Integer>(integerList);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
copy.remove(integer);
}
}
The forward/iterator method does not work when removing items. You can remove the element without error, but you will get a runtime error when you try to access removed items. You can't use the iterator because as pushy shows it will cause a ConcurrentModificationException, so use a regular for loop instead, but step backwards through it.
List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
int size= integerList.size();
//Item to remove
Integer remove = Integer.valueOf(3);
A solution:
Traverse the array in reverse order if you are going to remove a list element. Simply by going backwards through the list you avoid visiting an item that has been removed, which removes the exception.
//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
if (integerList.get(i).equals(remove) ) {
integerList.remove(i);
}
}
This snippet will always throw a ConcurrentModificationException.
The rule is "You may not modify (add or remove elements from the list) while iterating over it using an Iterator (which happens when you use a for-each loop)".
JavaDocs:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.
Hence if you want to modify the list (or any collection in general), use iterator, because then it is aware of the modifications and hence those will be handled properly.
Hope this helps.
I had that same problem but in case that I was adding en element into iterated list.
I made it this way
public static void remove(Integer remove) {
for(int i=0; i<integerList.size(); i++) {
//here is maybe fine to deal with integerList.get(i)==null
if(integerList.get(i).equals(remove)) {
integerList.remove(i);
}
}
}
Now everything goes fine because you don't create any iterator over your list, you iterate over it "manually". And condition i < integerList.size() will never fool you because when you remove/add something into List size of the List decrement/increment..
Hope it helps, for me that was solution.
If you use copy-on-write collections it will work; however when you use list.iterator(), the returned Iterator will always reference the collection of elements as it was when ( as below )
list.iterator() was called, even if another thread modifies the collection. Any
mutating methods called on a copy-on-write–based Iterator or ListIterator
(such as add, set, or remove) will throw an UnsupportedOperationException.
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new CopyOnWriteArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
This runs fine on Java 1.6
~ % javac RemoveListElementDemo.java
~ % java RemoveListElementDemo
~ % cat RemoveListElementDemo.java
import java.util.*;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
~ %
In my case I did it like this:
int cursor = 0;
do {
if (integer.equals(remove))
integerList.remove(cursor);
else cursor++;
} while (cursor != integerList.size());
Change Iterator for each into for loop to solve.
And the Reason is:
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
--Referred Java Docs.
Check your code man....
In the main method you are trying to remove the 4th element which is not there and hence the error.
In the remove() method you are trying to remove the 3rd element which is there and hence no error.

Using iterator on a TreeSet

SITUATION: I have a TreeSet of custom Objects and I have also used a custom Comparator. I have created an iterator to use on this TreeSet.
TreeSet<Custom> ts=new TreeSet<Custom>();
Iterator<Custom> itr=ts.iterator();
while(itr.hasNext()){
Custom c=itr.next();
//Code to add a new element to the TreeSet ts
}
QUESTION: Well I want to know that if I add a new element to the TreeSet within the while loop, then will that new element get sorted immediately. In other words, if I add a new element within the while loop and it is less than the one which I am currently holding in c, then in the next iteration will I be getting the same element in c as in the last iteration?(since after sorting, the newly added element will occupy a place somewhere before the current element).
If you add an element during your iteration, your next iterator call will likely throw a ConcurrentModificationException. See the fail-fast behavior in TreeSet docs.
To iterate and add elements, you could copy first to another set:
TreeSet<Custom> ts = ...
TreeSet<Custom> tsWithExtra = new TreeSet(ts);
for (Custom c : ts) {
// possibly add to tsWithExtra
}
// continue, using tsWithExtra
or create a separate collection to be merged with ts after iteration, as Colin suggests.
You will get a java.util.ConcurrentModificationException if you add an element into the TreeSet inside while loop.
Set<String> ts = new TreeSet<>();
ts.addAll(Arrays.asList(new String[]{"abb", "abd", "abg"}));
Iterator<String> itr = ts.iterator();
while(itr.hasNext()){
String s = itr.next();
System.out.println("s: " + s);
if (s.equals("abd"))
ts.add("abc");
}
###Output
Exception in thread "main" java.util.ConcurrentModificationException
public static void main(String[] args) {
TreeSet<Integer> ts=new TreeSet<Integer>();
ts.add(2);
ts.add(4);
ts.add(0);
Iterator<Integer> itr=ts.iterator();
while(itr.hasNext()){
Integer c=itr.next();
System.out.println(c);
//Code
ts.add(1);
}
}
Exception in thread "main" java.util.ConcurrentModificationException
This will come to all collections like List , Map , Set
Because when iterator starts it may be putting some lock on it .
if you iterate list using iterator then this exception will come. I think otherwise this loop will be infinite as you are adding element whole iterating.
Consider without iterator:
public static void main(String[] args) {
List<Integer> list=new ArrayList<Integer>();
list.add(2);
list.add(4);
list.add(0);
for (int i = 0; i < 3; i++) {
System.out.println(list.get(i));
list.add(3);
}
System.out.println("Size" +list.size());
}
this will be fine .
In order to avoid the ConcurrentModificationException you might want to check out my UpdateableTreeSet. I have even added a new test case showing how to add elements during a loop. To be more exact, you mark new elements for a later, deferred update of the set. This works quite nicely. Basically you do something like
for (MyComparableElement element : myUpdateableTreeSet) {
if (someCondition) {
// Add new element (deferred)
myUpdateableTreeSet.markForUpdate(
new MyComparableElement("foo", "bar", 1, 2)
);
}
}
// Perform bulk update
myUpdateableTreeSet.updateMarked();
I guess this is quite exactly what you need. :-)
To prevent the ConcurrentModificationException while walking.
Below is my version to allow high frequency insertion into the TreeSet() and allow concurrently iterate on it. This class use a extra queue to store the inserting object when the TreeSet is being iterating.
public class UpdatableTransactionSet {
TreeSet <DepKey> transactions = new TreeSet <DepKey> ();
LinkedList <DepKey> queue = new LinkedList <DepKey> ();
boolean busy=false;
/**
* directly call it
* #param e
*/
void add(DepKey e) {
boolean bb = getLock();
if(bb) {
transactions.add(e);
freeLock();
} else {
synchronized(queue) {
queue.add(e);
}
}
}
/**
* must getLock() and freeLock() while call this getIterator function
* #return
*/
Iterator<DepKey> getIterator() {
return null;
}
synchronized boolean getLock() {
if(busy) return false;
busy = true;
return true;
}
synchronized void freeLock() {
synchronized(queue) {
for(DepKey e:queue) {
transactions.add(e);
}
}
busy = false;
}
}
While the question has already been answered, I think the most satisfactory answer lies in javadoc of TreeSet itself
The iterators returned by this class's iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, >generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
To avoid the concurrent modification error that's bound to occur when you're doing the insertion, you could also create a temporary copy of the Set, iterate through the copy instead, and modify the original.

Categories

Resources