[英]concurrent modification exception with iterator
我对Java相当陌生,实际上是在编写键盘记录程序,并使其定期写入文件。 每当用户按下一个键时,它都会实例化一个NativeKeyEvent,该NativeKeyEvent调用“ paramString()”并将信息作为字符串添加到下面的arraylist中。
public static ArrayList<String> stringArray = new ArrayList<String>();
public synchronized String paramString() {
StringBuilder param = new StringBuilder(255);
// other code
stringArray.add(param.toString());
}
然后,在每个间隔处传递字符串数组,并将其写入下面的TimerTask线程中的文件...
public class SaveToArrayAndWriteTask extends TimerTask {
private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;
private static String str;
@Override
public synchronized void run() {
openFile();
writeToFile(anotherArray);
closeFile();
}
private static synchronized void writeToFile(ArrayList<String> localArray) {
Iterator<String> iterator = localArray.iterator();
try {
while (iterator.hasNext()) {
str = iterator.next().toString();
output.format("%s\n", str);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
这行'str = iterator.next()。toString();' 如果在程序录制/添加另一个按键时尝试遍历arraylist并将其写入文件,则抛出异常。 我认为通过将stringArray(正在被修改)放入anotherArray并将其作为参数传递将阻止这种情况的发生。 如您所见,我已经尝试过使用synced关键字,并且还尝试将其放入另一个线程中,并阅读了关于stackoverflow的其他各种文章,但无济于事。
解决此问题的最佳方法是什么?
您不是在复制ArrayList,而是在另一个引用相同的ArrayList。
private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;
应该是这样的:
private ArrayList<String> copy = new ArrayList<>(NativeKeyEvent.stringArray);
这将创建一个新数组ArrayList,其元素与NativeKeyEvent.stringArray
相同。
我建议使用getter而不是将stringArray
公开为公共变量。 getter应该复制stringArray
并返回它。 这样, stringArray
任何使用者都将在副本上进行操作,并且无法修改列表。
我想通过将stringArray(正在被修改)放入anotherArray
private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;
没有创建新的ArrayList。 anotherArray仍在引用同一对象。 您需要创建一个新的ArrayList,其中包含stringArray的元素。
private ArrayList<String> anotherArray = new ArrayList<>(NativeKeyEvent.stringArray);
一般而言,如果在迭代集合时对其进行修改,则会收到ConcurrentModificationException
。
您有两种选择:
困难的方法:同步对列表的访问,以便其他线程在迭代时阻塞
简单的方法:使用java.util.concurrent
包中的CopyOnWriteArrayList
列表实现,它为您完成了所有艰苦的工作
public static ArrayList<String> stringArray = new CopyOnWriteArrayList<String>();
而已。 不再需要,您可以删除所有同步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.