1

I am getting a ConcurrentModificationException on the following code:

private static List<Task> tasks = new LinkedList<Task>();
...
public void doTasks(){
    synchronized(tasks){
        Iterator<Task> it = tasks.iterator();

        while(it.hasNext()){
            Task t = it.next(); < Exception is always thrown on this line.

            if(t.isDone()){
                it.remove();
            } else {
                t.run();
            }
        }
    }
}
...
public void addTask(Task t){
    synchronized(tasks){
        tasks.add(t);
    }
}
...
public void clearTasks(){
    synchronized(tasks){
        tasks.clear();
    }
}

The Object "tasks" is not used anywhere else in the class. I'm not sure why I'm getting the exception. Any help would be greatly appreciated.

3
  • Which line is the exception on? Commented Apr 26, 2013 at 21:37
  • 1
    I would use an ExecutorService. You can submit tasks to it and it is built in. Commented Apr 26, 2013 at 21:38
  • I added that information regarding where the exception is thrown into the source. Commented Apr 26, 2013 at 21:42

2 Answers 2

3

This is your issue:

if(t.isDone()){
    ...
} else {
    t.run(); // probably changing the task, so consequently the list tasks
}

EDIT: you can't change the tasks list in the loop. Check out the ConcurrentModificationException documentation for more details.

Cheers!

Sign up to request clarification or add additional context in comments.

3 Comments

I read elsewhere that you can if you use Iterator.remove(). stackoverflow.com/questions/1655362/…
@idunnololz yup, you're absolutely right. remove is an optional operation so it can throw an UnsupportedOperationException, otherwise it's supported by the underlying Collection.
I'm inclined to say it's the t.run() cause the tasks t might be changed by run() ...
1

Found the bug! I forgot the scenario where the task ran in doTask() can actually call addTask(). However I am a bit confused why this can happen as I thought the "tasks" object would be locked by the doTask() function.

3 Comments

The Thread already has a lock so it works fine. synchronized prevents other Threads from acquiring the monitor on tasks but the Thread in question already has the monitor.
Exactly what @BoristheSpider said. The locks are reentrant, so if the thread tried to obtain the lock a second time, it would be granted. Ergo, Trinimon's answer was correct.
If they weren't reentrant, your thread would have deadlocked itself! Think about it: it would block on trying to add a task, and it wouldn't be able to unblock until it completed the doTask that's blocked by the attempt to add. It's like stopping your car at a stop sign and not starting it back up again until you're home.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.