java - 在 for each 循环中同步仍然会抛出 ConcurrentModificationExceptions

标签 java concurrency synchronized

我正在尝试在一个线程上迭代一个循环,如下所示:

for (UnitTask task : chain) {
    g.drawLine((int) task.getLocation().getX(), (int) task.getLocation().getY(), (int) currentPos.getX(), (int) currentPos.getY());
    g.fillOval((int) task.getLocation().getX() - 2, (int) task.getLocation().getY() - 2, 5, 5);
    currentPos = task.getLocation();
}

但是,我有另一个线程(Swing 事件线程)可以添加到这个对象。因此,ConcurrentModificationException。我尝试通过用 synchronized (chain) { ... } 包围代码来获得锁,但我仍然遇到错误。

作为一个 Java 同步新手,我有点困惑为什么。我希望这会使循环线程安全,但显然不是。

有趣的是,chain 是自定义类的一个实例,但它只是 LinkedList 的薄包装。列表本身是私有(private)的,外部类无法直接检索它(有显式添加/删除对象的方法),所以我不认为这会影响结果。

最佳答案

意义

synchronized (c) {
    ... code that uses c ...
}

  • 等待c解锁
  • 锁定c
  • 执行正文
  • 解锁c

因此,如果您在您的线程中进行同步,那么您的线程将等待 c 解锁,然后潜入。

现在,如果您同步修改cother 线程上的代码,该代码将继续执行并且修改 c 而不等待锁定。在一个线程中同步块(synchronized block)不会使另一个线程等待锁。如果另一个线程有这样一行

c.add(someOtherTask)

不在同步块(synchronized block)中,那么无论如何它都会执行添加。这是您异常(exception)的原因。这也是为什么即使将代码放在同步块(synchronized block)中的线程中也会看到异常的原因:您的代码是“按规则进行游戏”,但另一个线程根本不在乎。

但是要小心同步长时间运行的代码。正如 Stephen C 所说,您最好使用并发集合类型。

关于java - 在 for each 循环中同步仍然会抛出 ConcurrentModificationExceptions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12444586/

相关文章:

java - 将线程注册到 Phaser

java - Android 布局两个 ImageView 之间的 ScrollView

java - 无法访问的代码处理arduino通信

java - Mockito 中的 Spring @Value 字段注入(inject)

java同步问题

java - 同步有什么问题

java - 为什么 synchronized 不能正常工作?

JavaFx 不需要的白色角 - TextArea

concurrency - 同时处理一个 channel 会导致意外的输出

java - java IoC框架如何保证线程安全?