arraylist 上的并发修改
concurrent modification on arraylist
有很多并发的 mod 异常问题,但我找不到可以帮助我解决问题的答案。如果您找到了答案,请提供 link 而不是简单的否决票。
所以我最初在尝试搜索数组列表并删除元素时遇到并发 mod 错误。有一段时间,我通过创建第二个数组列表、将发现的元素添加到其中、然后在 for 循环外使用 removeAll() 来解决这个问题。这似乎可行,但是当我使用 for 循环从多个文件导入数据时,我开始再次并发 modification 异常,但由于某种原因断断续续。任何帮助将不胜感激。
这是有问题的具体方法(以及它调用的其他方法...):
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异常
在 java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
在 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()) {
又回到间歇性触发。我的意思是我第一次尝试导入数据(从 addData 方法触发 removeData 方法)它触发并发 mod 异常,但下一次尝试它推过失败并移动到另一个文件.我知道有很多这些并发的 mod 问题,但我没有找到任何对我的情况有帮助的东西,所以 link 其他答案非常受欢迎...
这不是怎么做,要在遍历 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 的同步集合。但是,你的代码可能会变得很慢。
有很多并发的 mod 异常问题,但我找不到可以帮助我解决问题的答案。如果您找到了答案,请提供 link 而不是简单的否决票。
所以我最初在尝试搜索数组列表并删除元素时遇到并发 mod 错误。有一段时间,我通过创建第二个数组列表、将发现的元素添加到其中、然后在 for 循环外使用 removeAll() 来解决这个问题。这似乎可行,但是当我使用 for 循环从多个文件导入数据时,我开始再次并发 modification 异常,但由于某种原因断断续续。任何帮助将不胜感激。
这是有问题的具体方法(以及它调用的其他方法...):
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异常 在 java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) 在 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()) {
又回到间歇性触发。我的意思是我第一次尝试导入数据(从 addData 方法触发 removeData 方法)它触发并发 mod 异常,但下一次尝试它推过失败并移动到另一个文件.我知道有很多这些并发的 mod 问题,但我没有找到任何对我的情况有帮助的东西,所以 link 其他答案非常受欢迎...
这不是怎么做,要在遍历 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 的同步集合。但是,你的代码可能会变得很慢。