繁体   English   中英

迭代器的并发修改异常

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM