Martin Kňažko
Martin Kňažko

Reputation: 3

How to loop arraylist from one thread ,while adding to it from other thread?

How to loop ArrayList from one thread ,while adding to it from other thread?

1) I have one thread which loop over ArrayList and perform some checks.

2) I have second thread which adds to end of ArrayList.

I have semaphore which pause first thread when second is running, but how do I implement this:

When second thread adds something to ArrayList , first thread will continue loop from point where it was paused without throwing java.util.ConcurrentModificationException?

Upvotes: 0

Views: 2108

Answers (3)

Gerald Mücke
Gerald Mücke

Reputation: 11132

If you're bound to use an ArrayList you have to synchronize access to it. But that still doesn't save you from ConcurrentModificationExeptions as this doen't necessarily has something to do with concurrency.

From JavaDoc

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

If you can ensure, only new items get appended to the list, you may just use an index and loop manually over it and not use an iterator. Once you reach the end of the queue, you start all over.

ArrayList q = new ArrayList<>();

//thread 1    
Object o = ...;
synchronized(q) {
  q.add(o); //append
}

//thread 2
int i = 0;
synchronized(q) {
  int size = q.size();
  for(; i < size; i++){
    Object o = q.get(i);
    //do something with o
  }
  if(i >= size) {
    i = 0;
  }
}

But doing it that way will lead you to a somewhat sequential behavior as either one or the other thread may operate at once on the list. The only "advantage" is that the threading model adds some randomness to the loop operation. So you could as well skip synchronization and concurrency and just do

q.add(o); //append 
//you may add a random condition, i.e. time interval, item count random number to trigger the loop process so it don't get exectued on each add
for(Object o : q){
  //do something with o 
}

Of course you can use a Safe-Copy as Nicolas wrote, but that's just a shallow copy of the container structure (list) and not of it's contents. So if you do that, be sure the items are thread safe or don't modify them.

In case the second thread occasionally removes an item from the end of list, you should better use a Queue. Java provides the Deque for that. One thread may add elements at one end while the other removes from the other. As you use it in multiple threads, and synchronizing manually sucks, you should better use a thread safe implementation and skip synchronization:

Deque q = new ConcurrentLinkedDeque<>();

//thread 1    
Object o = ...;
q.addFirst(o);

//thread 2
while(!q.isEmpty()){
    Object o = q.removeLast();
   //do something with o
}

Upvotes: 6

urag
urag

Reputation: 1258

The simplest solution is to use CopyonWritearrayList it is design to precisely for this kind of stuff but note that it is slower than usual ArrayList

Upvotes: 0

Nicolas Filotto
Nicolas Filotto

Reputation: 44965

Assuming that you cannot use a Queue like ConcurrentLinkedQueue, here is how you can proceed:

Here I assume that your checking is fast:

Thread 1:

synchronized(list) {
    for (MyClass obj : list) {
        // check what you want here
    }
}

Thread 2:

synchronized(list) {
    list.add(obj);
}

Here I assume that your checking is slow:

Thread 1:

List<MyClass> safeCopy;
synchronized(list) {
    safeCopy = new ArrayList<>(list);
}
for (MyClass obj : safeCopy) {
    // check what you want here
}

Thread 2:

Same as above

If you don't modify too often your list you should use CopyOnWriteArrayList it is thread safe already, read operations are very fast as there is no locking but write operations are slow because it rebuilds the whole list

Upvotes: 1

Related Questions