对arraylist的并发修改

时间:2015-06-12 16:29:12

标签: java for-loop arraylist concurrentmodification

有很多并发mod异常问题,但我找不到帮助我解决问题的答案。如果您找到答案,请提供链接而不是仅仅投票。

所以我在尝试搜索arraylist并删除元素时最初遇到并发mod错误。有一段时间,我通过创建第二个arraylist,将发现的元素添加到它,然后在for循环外使用removeAll()来解决它。这似乎工作,但当我使用for循环从多个文件导入数据时,我开始再次获得并发修改异常,但由于某种原因间歇性地。任何帮助将不胜感激。

这是具有问题的具体方法(以及它调用的其他方法......):

public static void removeData(ServiceRequest r) {
    readData();
    ArrayList<ServiceRequest> targets = new ArrayList<ServiceRequest>();
    for (ServiceRequest s : serviceQueue) {  
    //ConcurrentModification Exception triggered on previous line
        if ( 
            s.getClient().getSms() == r.getClient().getSms() && 
            s.getTech().getName().equals(r.getTech().getName()) && 
            s.getDate().equals(r.getDate())) {
                JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
                targets.add(s);
                System.out.print("targetted"); }
    }
    if (targets.isEmpty()) { System.out.print("*"); }
    else { 
        System.out.print("removed");
        serviceQueue.removeAll(targets); 
        writeData(); }
}
public static void addData(ServiceRequest r) {
    readData();
    removeData(r);
    if (r.getClient().getStatus().equals("MEMBER") || r.getClient().getStatus().equals("ALISTER")) {
        serviceQueue.add(r); } 
    else if (r.getClient().getStatus().equals("BANNED") || r.getClient().getStatus().equals("UNKNOWN")) {
        JOptionPane.showMessageDialog(null, "New Request failed: " + r.getClient().getSms() + " is " + r.getClient().getStatus() + "!", "ERROR: " + r.getClient().getSms(), JOptionPane.WARNING_MESSAGE);
    }
    else {
        int response = JOptionPane.showConfirmDialog(null, r.getClient().getSms() + " is " + r.getClient().getStatus() + "...", "Manually Overide?", JOptionPane.OK_CANCEL_OPTION);
        if (response == JOptionPane.OK_OPTION) {
            serviceQueue.add(r); }
    }
    writeData(); }

public static void readData() {
    try {
        Boolean complete = false;
        FileReader reader = new FileReader(f);
        ObjectInputStream in = xstream.createObjectInputStream(reader);
        serviceQueue.clear();
        while(complete != true) {   
            ServiceRequest test = (ServiceRequest)in.readObject();      
            if(test != null && test.getDate().isAfter(LocalDate.now().minusDays(180))) { 
                serviceQueue.add(test); }
                else { complete = true; }
        }
        in.close(); } 
    catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } 
}
public static void writeData() {
    if(serviceQueue.isEmpty()) { serviceQueue.add(new ServiceRequest()); }
    try {
        FileWriter writer = new FileWriter(f);
        ObjectOutputStream out = xstream.createObjectOutputStream(writer);
        for(ServiceRequest r : serviceQueue) { out.writeObject(r); }
        out.writeObject(null);
        out.close(); }
    catch (IOException e) { e.printStackTrace(); }
}

修改

这些更改会导致并发mod每次都触发而不是间歇性触发,我猜这意味着删除代码更好但现在错误触发it.remove();

public static void removeData(ServiceRequest r) {
    readData();
    for(Iterator<ServiceRequest> it = serviceQueue.iterator(); it.hasNext();) {
        ServiceRequest s = it.next();
        if ( 
            s.getClient().getSms() == r.getClient().getSms() && 
            s.getTech().getName().equals(r.getTech().getName()) && 
            s.getDate().equals(r.getDate())) {
                JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
                it.remove();  //Triggers here (line 195)
                System.out.print("targetted"); }
    }
    writeData(); }

线程“AWT-EventQueue-0”中的异常java.util.ConcurrentModificatio n异常     at java.util.ArrayList $ Itr.checkForComodification(ArrayList.java:901)     at java.util.ArrayList $ Itr.next(ArrayList.java:851)     at data.ServiceRequest.removeData(ServiceRequest.java:195)     at data.ServiceRequest.addData(ServiceRequest.java:209)&lt; ...&gt;

修改 经过一些搜索,我将for循环切换为:

        Iterator<ServiceRequest> it = serviceQueue.iterator();
        while(it.hasNext()) {

它又回到间歇性触发。我的意思是我第一次尝试导入数据(从addData方法触发removeData方法)它会触发并发mod异常,但是下一次尝试它会推迟失败并转移到另一个文件。我知道有很多这些并发的mod问题,但我找不到任何对我的情况有帮助的东西,所以非常欢迎链接到其他答案......

1 个答案:

答案 0 :(得分:1)

这不是如何做到这一点,在通过使用迭代器的List时删除元素。像那样:

List<ServiceRequest> targets = new ArrayList<ServiceRequest>();
for(Iterator<ServiceRequest> it = targets.iterator(); it.hasNext();) {
    ServiceRequest currentServReq = it.next();
    if(someCondition) {
        it.remove();
    }
}

如果你只有一个帖子,你就不会以这种方式得到ConcurrentModificationException。

如果代码中涉及多个线程,您可能仍会收到ConcurrentModificationException。解决此问题的一种方法是在集合(serviceQueue)上使用Collections.synchronizedCollection(...),因此您将获得不会产生ConcurrentModificationException的同步集合。但是,你的代码可能会变得很慢。