Anthony
Anthony

Reputation: 195

Concurrency issue with threads

I have a simple code, consisting of 4 threads (2 modify the data and 2 read the data). I just wrote this sample code to play around with Semaphor and I am not sure why I get ava.base/java.util.ArrayList$Itr.checkForComodification exception? Here are the source code and thanks for any insights.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static class InnerWriterSemaphoreThread implements Runnable {

    private final List<String> fList;
    private final Semaphore fWriteSem;

    InnerWriterSemaphoreThread(List<String> list, Semaphore w) {
        fList = list;
        fWriteSem = w;
    }

    private void prune() {
        System.out.println(Thread.currentThread().getName()+" in prune()..");
        for (String s : fList) {
            fList.remove(s);
        }
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        String text;
        while (true) {
            text = RandomTextGenerator.getRandomSNumbertring();
            try {
                while(!fWriteSem.tryAcquire()){
                    System.out.println(name+" waiting to accquire semaphore to write..");
                    Thread.sleep(0L,4);
                }
                if (fList.size() > 10) {
                    prune();
                }
                fList.add(text);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                fWriteSem.release();// notify readers that write has completed
                System.out.println(name+" finished writing, releasing semaphore..");
            }
        }//while()
    }//run()
    }//WriterSemaphoreThread
    public static class InnerReaderSemaphoreThread implements Runnable {

    private final List<String> fList;
    private final Semaphore fWriteSem;

    InnerReaderSemaphoreThread(List<String> list,Semaphore w) {
        fList = list;
        fWriteSem = w;
    }
    private void sleep(){
        try{
            Thread.sleep(0L, 4);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        while (true) {
            System.out.println(name + " in run()..");
            try {
                while(fList.isEmpty()){
                    System.out.println(name+" list is empty, going to sleep..");
                    sleep();
                }
                while(!fWriteSem.tryAcquire()){
                    System.out.println(name+" waiting to accquire semaphor to read..");
                    Thread.sleep(0l,4);
                }
                for (String text : fList) {
                    System.out.println(name + " reading from list " + text);
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally{
                fWriteSem.release(); //Notify threads who want to write to the list
                System.out.println(name+" finished reading, releasing semaphore and going to sleep..");
                sleep();
            }
        }
    }
    }//ReaderSemaphoreThread

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Semaphore r = new Semaphore(1);
        Thread th1 = new Thread(new InnerWriterSemaphoreThread(list, r), "Thread 1");
        Thread th2 = new Thread(new InnerReaderSemaphoreThread(list, r), "Thread 2");
        Thread th3 = new Thread(new InnerWriterSemaphoreThread(list, r), "Thread 3");
        Thread th4 = new Thread(new InnerReaderSemaphoreThread(list, r), "Thread 4");
        th2.start();
        th4.start();
        th1.start();
        th3.start();
    }
}

Above is the sample source code

Upvotes: 0

Views: 68

Answers (1)

Alex
Alex

Reputation: 866

As @assylias mentioned in comment it happens when you remove elements from list in foreach loop. Just replace

for (String s : fList) {
   fList.remove(s);
}

with

fList.clear();

Upvotes: 2

Related Questions