首页 文章

线程抛出java.util.ConcurrentModificationException [暂停]

提问于
浏览
-1

每次我运行程序时,这个线程抛出这个异常,我似乎无法找到它的原因 . 有人可以试着解释为什么会发生这种情况吗?

package GPS.gpsproject;

import GPS.Model.Event;
import GPS.Model.Vehicle;

import java.time.Duration;
import java.time.LocalDate;

import java.util.List;


public class Notify extends Thread {
    private List<Veiculo> vehicles;
    private Controler controler;

    public Notify(List<Veiculo> vehicles, Controlador controler) {
        this.controler= controler;
        this.vehicles= vehicles;   
    }

    @Override
    public void run() {
        while (true) {
            for (Vehicle v : vehicles) {
                for (Event e : v.getEvents()) {
                    if (Duration.between(e.getData().atStartOfDay(), LocalDate.now().atStartOfDay()).toDays() < e.getDiasAntes() && !e.isNotified()) {
                        e.setNotified(true);
                        controler.sendNotification("Notification", e.getDesc());

                }
            }
        }
    }
}

例外:

Exception in thread "Thread-4" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at GPS.gpsproject.Notifica.run(Notify.java:25)

sendNotification()方法只是通知用户该事件

3 回答

  • 0

    当thread2修改 ArrayList (例如,添加新元素)时,thread1使用它进行迭代

    for (Vehicle v : vehicles)

    thread1将抛出 ConcurrentModificationException ,这称为fail-fast .

    您可能想要使用CopyOnWriteArrayList

    此数组在迭代器的生命周期内永远不会更改,因此无法进行干扰,并且保证迭代器不会抛出ConcurrentModificationException . 自迭代器创建以来,迭代器不会反映列表的添加,删除或更改 .

  • 1

    我假设 NotificaNotify 指的是同一个类(其中一个必须是拼写错误) . 您正在将 List<Veiculo> 传递给 Notifica 类的构造函数 . 然后在 run() 方法中迭代 List .

    假设您在嵌套for循环中调用的方法不会修改 vehicles 列表或 Event 的任何内部集合,这意味着当您迭代它们时,某些其他线程必须在任何这些集合中进行结构更改 .

    由于 vehicles 在迭代时不应进行结构修改,因此可能的解决方案可能是在构造函数中创建一个副本:

    this.vehicles = new ArrayList<>(vehicles);
    

    请注意,这仅在其他线程不在属于 Veiculo 实例的 Event 的内部集合中进行结构更改时才起作用,因为这是一个浅表副本 .

  • -2

    导致该问题的原因是,您可能只创建一个车辆ArrayList并将相同的ArrayList传递给多个线程创建 . 在这种情况下,多个线程将访问相同的ArrayList对象 . 要避免相同的情况,您可以在创建Notify类对象时创建新的ArrayList并将其传递给构造函数,或者您可以更改Notify类下面的代码广告 .

    public Notify(List<Veiculo> vehicles, Controlador controler) {
            this.controler= controler;
            this.vehicles= new ArrayList<Veiculo>(vehicles);   
    }
    

相关问题