concurrent modification on arraylist

限于喜欢 提交于 2019-12-25 18:27:08

问题


There are a lot of concurrent mod exception questions, but I'm unable to find an answer that has helped me resolve my issue. If you find an answer that does, please supply a link instead of just down voting.

So I originally got a concurrent mod error when attempting to search through an arraylist and remove elements. For a while, I had it resolved by creating a second arraylist, adding the discovered elements to it, then using removeAll() outside the for loop. This seemed to work, but as I used the for loop to import data from multiple files I started getting concurrent modification exceptions again, but intermittently for some reason. Any help would be greatly appreciated.

Here's the specific method having the problem (as well as the other methods it calls...):

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(); }
}

EDIT

The changes cause the concurrent mod to trigger every time rather than intermittently, which I guess means the removal code is better but the error now triggers at 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(); }

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificatio nException 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) <...>

EDIT After some more searching, I've switch the for loop to:

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

and it's back to intermittently triggering. By that I mean the first time I attempt to import data (the removeData method is being triggered from the addData method) it triggers the concurrent mod exception, but the next try it pushes past the failure and moves on to another file. I know there's a lot of these concurrent mod questions, but I'm not finding anything that helps in my situation so links to other answers are more than welcome...


回答1:


This is not how to do it, to remove elements while going through a List you use an iterator. Like that :

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

And you will not get ConcurrentModificationException this way if you only have one thread.

If there is multiple threads involved in your code, you may still get ConcurrentModificationException. One way to solve this, is to use Collections.synchronizedCollection(...) on your collection (serviceQueue) and as a result you will get a synchronized collection that will not produce ConcurrentModificationException. But, you code may become very slow.



来源:https://stackoverflow.com/questions/30807982/concurrent-modification-on-arraylist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!