尽管使用同步对集合进行排序,但仍获取 ConcurrentModificationException
Getting ConcurrentModificationException despite using synchronized to sort a Collection
我尝试使用线程方法对集合进行排序,其中方法单独调用比较器 classes
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);
}
}
每个线程方法如下所示:
public class ThreadedIDSort implements Runnable, EmployeeInterface {
public synchronized void run(){
employeeList.sort(new IDComparator());
}
}
ID Compartator class如下:
public class IDComparator implements Comparator<Employee> {
@Override
public int compare(Employee a, Employee b) {
return a.getID()-b.getID();
}
}
employeeList 是具有属性 name、id、salary 和 post:
的对象列表
ArrayList<Employee> employeeList=new ArrayList<>();
虽然我在 运行 方法之前添加了同步,但编辑列表仍然会出现 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)
我正在尝试使用线程同时使用名称、post 和 ID 进行排序。
A ConcurrentModification
也可以出现在单线程应用程序中。当集合被修改和迭代时,它们就会发生。这可以像下面这样简单:
for (String s : myStringList) {
if ("X".equals(s)) {
myStringList.remove(s);
}
}
请注意,来自 java.util.concurrent
的 so-called 并发集合旨在支持这一点,但来自 java.util
的大多数(全部?)都有同样的问题,即使你应用同步。
没有看到 employeeList
到底是什么,以及 IDComparator
做了什么,很难说为什么在这种特定情况下抛出异常。
Rob Spoor 解释了为什么 ConcurrentModificationException
不一定与线程有关。而且,你应该知道这一点:
您示例中 run()
方法的 synchronized
关键字无效。
当你写一个同步方法时,
public synchronized void bar() {
...
}
这和你写的一样,
public void bar() {
synchronized(this) {
...
}
}
在您的示例中,您提交给执行程序服务的三个任务中的每一个都是不同的 Runnable
对象。关键字 this
在三个 run()
方法中分别引用不同的对象。三个不同的线程在三个不同的对象上同步就等于根本没有同步。
仅当线程在相同 对象上同步时,同步才有意义。规则是,不允许两个线程同时在 同一对象 上同步。
问题是相同的 'employeeList' 被 运行 不同的线程同时修改。
其中一个选项是克隆 employeeList 并分配单独的列表进行排序。
示例:
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
我尝试使用线程方法对集合进行排序,其中方法单独调用比较器 classes
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);
}
}
每个线程方法如下所示:
public class ThreadedIDSort implements Runnable, EmployeeInterface {
public synchronized void run(){
employeeList.sort(new IDComparator());
}
}
ID Compartator class如下:
public class IDComparator implements Comparator<Employee> {
@Override
public int compare(Employee a, Employee b) {
return a.getID()-b.getID();
}
}
employeeList 是具有属性 name、id、salary 和 post:
的对象列表ArrayList<Employee> employeeList=new ArrayList<>();
虽然我在 运行 方法之前添加了同步,但编辑列表仍然会出现 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)
我正在尝试使用线程同时使用名称、post 和 ID 进行排序。
A ConcurrentModification
也可以出现在单线程应用程序中。当集合被修改和迭代时,它们就会发生。这可以像下面这样简单:
for (String s : myStringList) {
if ("X".equals(s)) {
myStringList.remove(s);
}
}
请注意,来自 java.util.concurrent
的 so-called 并发集合旨在支持这一点,但来自 java.util
的大多数(全部?)都有同样的问题,即使你应用同步。
没有看到 employeeList
到底是什么,以及 IDComparator
做了什么,很难说为什么在这种特定情况下抛出异常。
Rob Spoor 解释了为什么 ConcurrentModificationException
不一定与线程有关。而且,你应该知道这一点:
您示例中 run()
方法的 synchronized
关键字无效。
当你写一个同步方法时,
public synchronized void bar() {
...
}
这和你写的一样,
public void bar() {
synchronized(this) {
...
}
}
在您的示例中,您提交给执行程序服务的三个任务中的每一个都是不同的 Runnable
对象。关键字 this
在三个 run()
方法中分别引用不同的对象。三个不同的线程在三个不同的对象上同步就等于根本没有同步。
仅当线程在相同 对象上同步时,同步才有意义。规则是,不允许两个线程同时在 同一对象 上同步。
问题是相同的 'employeeList' 被 运行 不同的线程同时修改。
其中一个选项是克隆 employeeList 并分配单独的列表进行排序。
示例:
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