迭代器的并发修改异常

时间:2014-07-29 12:53:35

标签: java exception arraylist concurrency iterator

我对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();
    }
}

行&#39; str = iterator.next()。toString();&#39;如果它在程序记录/添加另一个键击时尝试迭代arraylist将其写入文件,则抛出异常。我想通过将stringArray(正在被修改)放入anotherArray并将其作为参数传递将阻止这种情况发生。正如您所看到的,我已尝试使用synchronized关键字,我也尝试将其放入另一个线程,并在stackoverflow上阅读了其他各种帖子,但无济于事。

解决此问题的最佳方法是什么?

3 个答案:

答案 0 :(得分:0)

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

private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;

应该是这样的:

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

这将创建一个 new ArrayList,其元素与NativeKeyEvent.stringArray相同。

我建议使用getter而不是将stringArray公开为公共变量。 getter应该复制stringArray并返回它。这样,stringArray的任何消费者都将在副本上运行,并且无法修改列表。

答案 1 :(得分:0)

  

我想通过将stringArray(正在修改)放入anotherArray

private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;

不创建新的ArrayList。 anotherArray仍然引用同一个对象。 您需要创建一个包含stringArray元素的新ArrayList。

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

答案 2 :(得分:0)

一般来说,如果您在迭代时修改某个集合,那么您将获得ConcurrentModificationException

您有两种选择:

困难的方法:同步访问列表,以便其他线程在您重复迭代时阻止

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

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

那就是它。没有更多需要,您可以删除所有同步。