Using iterator over for-loop in concurrent java app - java

class Nodes has getNodes() method, which is not synchronized. But List<Node> nodes - is synchronized. Many threads could be connected to it, changing nodes in it.
Like this:
class Nodes {
List<Node> nodes = Collections.synchronizedList(new ArrayList<Node>() );
public List<Nodes> getNodes() { return nodes; }
...
}
Client code:
Nodes nodes;
synchronized(nodes) {
for(Node node: nodes.getNodes()) {
...
}
}
I do not have interrogation tests for that, but:
Should I use while(iterator.hasNext()) { var = iterator.next() } instead of for-loop ?
Because I know that when I try to delete nodes.remove(node) inside for-loop it fails with ConcurentModificationException.
EDIT: (related issue)
If iterator is good stuff to use, then having this code (client code):
Iterator<Node> iter = nodes.getNodes().iterator();
while (iter.hasNext()) { // line 1
Node node = iter.next(); // line 2
}
It is not safe anyway:
1. thread1 goes to line 1, hoping that now iter would return him next() value.
2. but at that moment thread2 delete that value.
3. thread1 has Exception and fails.
Does it mean that I should do locking on client side anyway. This is what I don't want to do.
One of the solutions I have:
while (iter.hasNext()) {
try {
Node node = iter.next();
...
} catch (NoSuchElementException ex) {continue;} // handle exception - do more try
}
EDIT:
Answer for my case was: to use CopyOnWriteArrayList. I can even stay with for-loop with it.
But another option: Just return client a copy of the list to let them know whatever they want with it. Because it is kind of strange (inconsistent) providing 'snapshot iterator' AND real data in the list at the same time.

Iterator.remove is the only safe way to modify a collection during iteration
Source: The Collection Interface tutorial

You should use an iterator like you have suggest, but instead of doing a nodes.delete() (which is really a nodes.remove(...) ) you should instead do iterator.remove()
You have updated your question. Here's an updated answer addressing the 'atomicity' of the iterator. If you want your iterator to have a 'snapshot' of the values at the time it (the iterator) was created, then you can use the Concurrent set of collections in java.util.concurrent: like CopyOnWriteArrayList

What is even better:
To use:
private List<Node> defensiveCopyNodeList() {
List<Node> nodesListCopy = Lists.newLinkedList();
synchronized (nodesList) {
nodesListCopy = ImmutableList.copyOf(nodesList); // Google [Guava lib][1]
}
return nodesListCopy;
}
Then in getter:
public List<Node> getNodes() {
return defensiveCopyNodeList();
}
Then it allows us to use safely not only iterator but and data itself.

Related

How to make a list perform like a queue and still return values?

I'm trying to write a program using Kahn's algorithm, sort of relating to BFS. Since the Queue and the List have exact keys being put in, is there anyways to remove the queue and make the list perform just like a queue and still return values? I was told to keep the preference for the List instead of removing the keys like what a queue does. I'm not sure how to do it though. Any suggestion is appreciated. Here's one part of my program.
private static List<Job> topologicalSortBFS(final List<Job> jobs) //Kahn's
{
final List<Job> sorted = new ArrayList<>(jobs.size());
final Map<Job, Integer> inCount = new HashMap<>(jobs.size());
final Queue<Job> queue = new ArrayDeque<>();
for (final Job j : jobs)
{
/* Associate every node with the amount of nodes it requires. */
final int in = j.inbound.size();
inCount.put(j, in);
/* If the node requires nothing, then add to queue and sorted list. */
if (in == 0)
{
sorted.add(j);
queue.add(j);
}
}
while (!queue.isEmpty())
{
final Job current = queue.poll(); // poll = pop
for (final Job neighbor : current.outbound)
{
/* Remove an outgoing connection without modifying the node. */
final int updatedIncount = inCount.get(neighbor) - 1;
inCount.put(neighbor, updatedIncount);
/* If node is now considered a leaf, its requirements were met. */
if (updatedIncount == 0)
{
sorted.add(neighbor);
queue.add(neighbor);
}
}
}
return sorted;
}
In your given code, only the poll( ) method is not available for the List object. However, poll( ) works in FIFO manner, returning and removing the topmost object from the queue. Alternatively, for a List you can get the first element using the get(index) method with index value 0 and also remove it. But you should consider using a LinkedList as for the remove( ) operation all the elements in ArrayList will be shifted for each removal, which is a costly operation. Also, LinkedList has the poll( ) method as it implements the Queue interface.
NOTE: Queue fits best for the given example, my answer is just a workaround to used a List as per your question.

Not getting Concurrent modification exception [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.

java while (LinkedList.iterator().hasNext()) does not work

I have the following while loop, if I put this.boatTripsList.iterator().hasNext() in the while loop condition, it throws error. When I create iterator then put in the while loop condition, it will work then. Why is this? Thanks & Regards. (the second version throws error)
public Journey(List<BoatTrip> trips) {
this.boatTripsList = new LinkedList<BoatTrip>();
Iterator<BoatTrip> iterator = trips.iterator();
//add the given boat trips to the boattrips list
while (iterator.hasNext()) {
BoatTrip thistrip = iterator.next();
this.boatTripsList.add(thistrip);
}
}
public Journey(List<BoatTrip> trips) {
this.boatTripsList = new LinkedList<BoatTrip>();
//add the given boat trips to the boattrips list
while (trips.iterator().hasNext()) {
BoatTrip thistrip = iterator.next();
this.boatTripsList.add(thistrip);
}
}
This is normal: if your while condition is while(trips.iterator().hasNext()), you create a new iterator each time. If your list is not empty, the condition will therefore always be true...
While in the loop itself, you use the iterator you created before entering the loop... As a result, you'll get a NoSuchElementException when this iterator is empty.
Use:
final Iterator<Whatever> = list.iterator();
Whatever whatever;
while (iterator.hasNext()) {
whatever = iterator.next();
// do whatever stuff
}
But for walking lists, a foreach loop is preferred:
for (final BoatTrip trip: tripList)
// do whatever is needed
And if you want to add the contents of a list to another, use .addAll():
// no need for the "this" qualifier, there is no name conflict
boatTripList.addAll(trips);
You aren't using the iterator you requested on the first line of your code there - you're requesting a new one each time, so it will always have a next.
A call to .iterator() obtains a new iterator. If you do that in the loop, you will always obtain a new iterator rather than iterating over an existing iterator.
this.boatTripsList.iterator().hasNext() is wrong
this.boatTripsList.hasNext() is correct

ConcurrentModificationException in LinkedList

I am trying to designing a software that convert a flowchart into java or any other code. However I repeatedly getting the ConcurrentModificationException..
But I can't use a boolean to prevent concurrentModification, because access to the linked list happens in various places.
So as a solution I created the below adapter class. However it also throws the same exception from next method. Are there any other solution or if can, plz let me know how to modify my codes...
thank you very much...
import java.util.Iterator;
import java.util.LinkedList;
public class LinkedListAdapter<T> extends LinkedList<T>{
#Override
public boolean add(T t){
boolean b;
synchronized(this){
b = super.add(t);
}
return b;
}
#Override
public T remove(){
T t;
synchronized(this){
t = super.remove();
}
return t;
}
#Override
public Iterator<T> iterator(){
final LinkedListAdapter<T> adap = this;
return
new Iterator<T>(){
private Iterator<T> iter;
{
synchronized(adap){
iter = LinkedListAdapter.this.getIterator();
}
}
#Override
public boolean hasNext() {
boolean b;
synchronized(adap){
b = iter.hasNext();
}
return b;
}
#Override
public T next() {
T t;
synchronized(adap){
t = iter.next();
}
return t;
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
protected Iterator<T> getIterator() {
Iterator<T> iter;
synchronized(this){
iter = super.iterator();
}
return iter;
}
}
The ConcurrentModificationException is usually thrown when iterating through the list and in the same time usually another thread or even the same loop tries to modify (add / remove) the contents of the list.
Using a synchronizedList or a synchronized list still has to be synchronised externally when iterating over it.
If you use ConcurrentLinkedQueue you don't have these issues.
Queue<Task> tasks = new ConcurrentLinkedQueue<Task>();
tasks.add(task); // thread safe
tasks.remove(task2); // thread safe
for(Task t: tasks) // can iterate without a CME.
Note: if you are using a queue with another thread I suggest you use an ExecutorService as this combines a Queue with a ThreadPool and make working with "background" thread much easier.
why not use LinkedBlockingQueue? http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html
BTW, it's not neceserally have to do with synchronization. a code like this:
for(Value v : valuesList){
valueslist.add(new Value());
}
would cause this exception as well. check your code for possible modifications of the list when it's being iterated over.
This happens when you iterate over the list and add elements to it in the body of the loop. You can remove elements safely when you use the remove() method of the iterator but not by calling any of the remove() methods of the list itself.
The solution is to copy the list before you iterate over it:
List<T> copy = new ArrayList<T>( list );
for( T e : copy ) {
... you can now modify "list" safely ...
}
Java collections are fail-fast, that means that all existing Iterators become invalid the moment the underlying collection is modified - synchronizing the modification does not stop the list from invalidating all iterators.
As a workaround you can create a copy of the list to iterate over or postpone modifications until the iteration is finished. To remove entries you can also use the iterator.remove() method which keeps the iterator itself valid.
List<X> myList = ....
List<X> myThreadSafeList = synchronizedList(myList);
synchronizedList(myList)
Notice the following statement in the JavaDoc:
It is imperative that the user manually synchronize on the returned list when iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
The answer here: Why am I getting java.util.ConcurrentModificationException? helped me a lot.
I will copy and paste it here in case anyone is looking to fix this error:
When you iterate through a list, you can't remove items from it. Doing so causes the exception.
Do:
int size = list.size();
for (int i = 0 ; i< size ; i++) {
list.add(0,"art");
list.remove(6);
System.out.println(list);
}

How to fix java.util.ConcurrentModificationException error when trying traverse in ArrayList

I'm trying to add new object to my ArrayList if it satisfy the condition.
But it got me this ConcurrentModificationExeption when I tried to run it. Hope you could help me:
public void addTaskCollection(Task t){
ListIterator<Task> iterator = this.taskCollection.listIterator();
if(this.taskCollection.isEmpty())
this.taskCollection.add(t);
while (iterator.hasNext()){
if(t.isOverlapped(iterator.next()))
this.taskCollection.add(t);
}
}
And here is the exeption error
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at Diary.addTaskCollection(Diary.java:36)
at Test.main(Test.java:50)
Java Result: 1
Replace your code with:
ListIterator<Task> iterator = this.taskCollection.listIterator();
boolean marker = false;
if(taskCollection.isEmpty())
this.taskCollection.add(t);
else {
while (iterator.hasNext()) {
if(iterator.next().isOverlapped(t) == false)
marker = true;
}
}
if (marker == true)
taskCollection.add(t);
to avoid ConcurrentModificationException.
copy the array and change the original.
It seems you encounter a race condition. Multiple threads are accessing / modifying the same collection. Use a thread-safe List implementation.
Also, you must not modifying the collection (adding / removing) while iterating on it with an Iterator.
EDIT
ConcurrentModificationExeption sounds like taskCollection is accessed and modified by multiple threads at the same time (we can not say regarding the piece of code you provide if your program is single or multi threaded). If you share taskCollection between several threads, use a thread-safe list implementation.
But, the error here is actually clearly due to the fact that you add an element to the collection between the moment you get an iterator on it and the moment you use this iterator. To fix that copy the new elements in temporary list and add them all in once at the end of the iteration.
Re-formatted Truong's answer from comments:
ListIterator<Task> iterator = this.taskCollection.listIterator();
boolean marker = false;
if(taskCollection.isEmpty())
this.taskCollection.add(t);
else {
while (iterator.hasNext()) {
if(iterator.next().isOverlapped(t) == false)
marker = true;
}
if (marker == true)
taskCollection.add(t);
}
Maintain two iterators.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Example_v3 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
// Insert some sample values.
list.add("Value1");
list.add("Value2");
list.add("Value3");
// Get two iterators.
Iterator<String> ite = list.iterator();
Iterator<String> ite2 = list.iterator();
// Point to the first object of the list and then, remove it.
ite.next();
ite.remove();
/* The second iterator tries to remove the first object as well. The object does
* not exist and thus, a ConcurrentModificationException is thrown. */
ite2.next();
ite2.remove();
}
}

Categories