同时修改数组列表 [英] concurrent modification on arraylist

查看:144
本文介绍了同时修改数组列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

  public static void removeData(ServiceRequest r){
readData();
ArrayList< ServiceRequest> targets = new ArrayList< ServiceRequest>();
for(ServiceRequest s:serviceQueue){
// ConcurrentModification前一行触发的异常
if(
s.getClient()。getSms()== r.getClient() .getSms()&&
s.getTech()。getName()。equals(r.getTech()。getName())&&
s.getDate()。equals getSms()+的服务请求+ s.getTech()。getName()+on+s.getDate())){
JOptionPane.showMessageDialog(null,s.getClient s.getDate()。toString()+已被删除!);
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);
$ b其他{
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()); }
尝试{
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.getTech()。getName()+on+ s.getDate()。toString()+has been removed!);
it.remove(); //触发这里(第195行)
System.out.print(targetted); }
}
writeData(); }

线程中的异常AWT-EventQueue-0java.util.ConcurrentModificatio
nException $ java.util.ArrayList
$ Itr.checkForComodification(ArrayList.java:901)$ b $ java.util.ArrayList $ Itr.next(ArrayList.java:851)
at data.ServiceRequest .removeData(ServiceRequest.java:195)
at data.ServiceRequest.addData(ServiceRequest.java:209)< ...>




经过一些更多的搜索,我已经把for循环切换到:

  Iterator< ServiceRequest> it = serviceQueue.iterator(); (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();




$ b

如果你只用这种方法,你将不会得到ConcurrentModificationException有一个线程。



如果代码中包含多个线程,则可能仍会收到ConcurrentModificationException。解决这个问题的一个方法是在你的集合(serviceQueue)上使用Collections.synchronizedCollection(...),结果你将得到一个同步的集合,不会产生ConcurrentModificationException。但是,你的代码可能会变得非常慢。


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...

解决方案

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.

这篇关于同时修改数组列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆