Java 迭代器并发修改异常

Java 迭代器并发修改异常,java,exception,arraylist,concurrency,iterator,Java,Exception,Arraylist,Concurrency,Iterator,我对java相当陌生,基本上我正在编写一个键盘记录器,并让它定期写入文件。每次用户按下一个键,它就会实例化一个NativeKeyEvent,该事件调用“paramString”,并将信息作为字符串添加到下面的arraylist中 public static ArrayList<String> stringArray = new ArrayList<String>(); public synchronized String paramString() { Stri

我对java相当陌生,基本上我正在编写一个键盘记录器,并让它定期写入文件。每次用户按下一个键,它就会实例化一个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放入另一个数组并将其作为参数传递可以阻止这种情况的发生。正如你所看到的,我尝试过使用synchronized关键字,我也尝试过将它放到另一个线程中,并阅读了stackoverflow上的其他文章,但都没有用


解决这个问题的最好办法是什么

您没有复制ArrayList,只是对同一ArrayList进行了另一次引用

private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;
应该是这样的:

private ArrayList<String> copy = new ArrayList<>(NativeKeyEvent.stringArray);
这将使用与NativeKeyEvent.stringArray相同的元素创建一个新的ArrayList

private ArrayList<String> anotherArray = new ArrayList<>(NativeKeyEvent.stringArray);
我建议使用getter,而不是将stringArray公开为公共变量。getter应该创建stringArray的副本并返回该副本。这样,stringArray的任何使用者都将对副本进行操作,并且不可能修改列表

我想把正在修改的stringArray放到另一个数组中

未创建新的ArrayList。另一个数组仍在引用同一对象。 您需要创建一个包含stringArray元素的新ArrayList

private ArrayList<String> anotherArray = new ArrayList<>(NativeKeyEvent.stringArray);

一般来说,如果在对集合进行迭代时对其进行修改,将得到ConcurrentModificationException

你有两个选择:

困难的方法是:同步对列表的访问,以便其他线程在迭代时阻塞

简单的方法是:使用包中的列表实现,它为您完成所有的艰苦工作

public static ArrayList<String> stringArray = new CopyOnWriteArrayList<String>();

就这样。不需要更多,您可以删除所有同步

很好,完全解决了这个问题。我已经把第一个arraylist定为私有。现在不创建新的arraylist似乎是一个愚蠢的错误。谢谢你的帮助!谢谢,我一定会收拾好的!谢谢!忽略创建新arraylist,新手错误!干杯