【问题标题】:concurrent modification exception with iterator带有迭代器的并发修改异常
【发布时间】:2014-09-20 20:30:03
【问题描述】:

我对 java 还很陌生,我基本上是在编写一个键盘记录器,并让它定期写入文件。每次用户按下一个键时,它都会实例化一个调用“paramString()”的 NativeKeyEvent,并将信息作为字符串添加到下面的数组列表中......

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 并将其作为参数传递可以阻止这种情况的发生。如您所见,我尝试使用 synchronized 关键字,也尝试将其放入另一个线程并阅读了有关 stackoverflow 的各种其他帖子,但无济于事。

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

【问题讨论】:

    标签: java exception arraylist concurrency iterator


    【解决方案1】:

    您不是在复制 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 的任何消费者都将对副本进行操作,并且无法修改列表。

    【讨论】:

    • 完美解决了这个问题。我已经将第一个数组列表设为私有。现在不创建新的数组列表似乎是一个愚蠢的错误。感谢您的帮助!
    【解决方案2】:

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

    private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;
    

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

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

    【讨论】:

    • 谢谢!俯瞰新建arraylist,菜鸟错误!干杯。
    【解决方案3】:

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

    你有两个选择:

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

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

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

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

    【讨论】:

    • 谢谢,我一定会整理好!
    猜你喜欢
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 2015-09-03
    • 2018-10-21
    • 1970-01-01
    相关资源
    最近更新 更多