簡體   English   中英

對數組列表的並發修改

[英]concurrent modification on arraylist

有很多並發的 mod 異常問題,但我無法找到幫助我解決問題的答案。 如果您找到答案,請提供一個鏈接,而不是僅僅投反對票。

所以我最初在嘗試搜索數組列表並刪除元素時遇到了並發 mod 錯誤。 有一段時間,我通過創建第二個數組列表,將發現的元素添加到其中,然后在 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();處觸發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 nException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851)在 data.ServiceRequest.removeData(ServiceRequest.java:195) 在 data.ServiceRequest.addData(ServiceRequest.java:209) <...>

編輯經過更多搜索后,我已將 for 循環切換為:

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

它又回到間歇性觸發。 我的意思是當我第一次嘗試導入數據時(removeData 方法是從 addData 方法觸發的),它會觸發並發 mod 異常,但下一次嘗試它會跳過失敗並移至另一個文件。 我知道有很多這些並發的 mod 問題,但我沒有找到任何對我的情況有幫助的東西,所以非常歡迎指向其他答案的鏈接......

這不是如何做到的,在使用迭代器遍歷 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 的同步集合。 但是,您的代碼可能會變得很慢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM