Home > Mobile >  Getting ConcurrentModificationException despite using synchronized to sort a Collection
Getting ConcurrentModificationException despite using synchronized to sort a Collection

Time:04-24

I tried to sort the collection using threaded methods where the methods call comparator classes individually

public class ThreadedSort{
   public ThreadedSort(){
       ThreadedIDSort idSort=new ThreadedIDSort();
       ThreadedNameSort nameSort=new ThreadedNameSort();
       ThreadedSalarySort salarySort=new ThreadedSalarySort();

        ExecutorService threadExecutor=Executors.newCachedThreadPool();

        threadExecutor.execute(idSort);
        threadExecutor.execute(nameSort);
        threadExecutor.execute(salarySort);

   }
}

Each threaded method looks like this:

public class ThreadedIDSort implements Runnable, EmployeeInterface {
    public synchronized void run(){
        employeeList.sort(new IDComparator());
    }
  }

The ID Compartator class is as follows:

public class IDComparator implements Comparator<Employee> {
    @Override
    public int compare(Employee a, Employee b) {
        return a.getID()-b.getID();
    }

}

The employeeList is a list of objects having attributes name, id, salary and post:

ArrayList<Employee> employeeList=new ArrayList<>();

Though I added synchronized before run method, editing the list still gives ConcurrentModificationException

Exception in thread "pool-2-thread-2" Exception in thread "JavaFX Application Thread" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList.sort(ArrayList.java:1723)
    at Client.Sort.Threaded.ThreadedNameSort.run(ThreadedNameSort.java:9)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:831)

I am trying to sort using name, post and ID all at once using threads.

CodePudding user response:

Rob Spoor explained why ConcurrentModificationException isn't necessarily about threading. But also, you should know this:

The synchronized keyword on the run() method in your example has no effect.

When you write a synchronized method,

    public synchronized void bar() {
        ...
    }

That's the same as if you wrote,

    public void bar() {
        synchronized(this) {
             ...
        }
    }

In your example, each of the three tasks that you submit to the executor service is a different Runnable object. The keyword, this, refers to a different object in each of the three run() methods. Three different threads synchronizing on three different objects is the same as no synchronization at all.

Synchronization is only meaningful when the threads synchronize on the same object. The rule is, no two threads will ever be allowed to synchronize on the same object at the same time.

CodePudding user response:

A ConcurrentModification can also occur in single threaded applications. They occur when a collection is both modified and iterated over. That can be as simple as the following:

for (String s : myStringList) {
    if ("X".equals(s)) {
        myStringList.remove(s);
    }
}

Note that the so-called concurrent collections, from java.util.concurrent, have been designed to support this, but most (all?) from java.util have the same issue, even if you apply synchronisation.

Without seeing what employeeList is exactly, and what IDComparator does, it's difficult to say why the exception is thrown in this specific case.

CodePudding user response:

The issue is with same 'employeeList' being modified by concurrently running different threads.

One of the options is to clone the employeeList and assign separate list for sorting.

Example:

ArrayList<Employee> employeeList=new ArrayList<>();

ArrayList<Employee>  employeeListByName = employeeList.clone();

ArrayList<Employee>  employeeListBySalary = employeeList.clone();

// use copy of list in respective thread

ThreadedIDSort  -> use employeeList
ThreadedNameSort -> use employeeListByName
ThreadedSalarySort -> use employeeListBySalary
  • Related