java - CopyOnWriteArrayList迭代器与多线程不一致?

标签 java multithreading concurrency iteration

我目前正在使用 ExecutorService 在 CopyOnWrite ArrayLists 中发送批量字符串以进行并行处理,其中处理这些列表的 Runnable 任务需要迭代列表并对每个字符串进行处理。

在遇到常规 ArrayList 的并发问题后,我尝试使用 CopyOnWriteArrayLists,因为它们是线程安全的,但我的结果现在不一致。也就是说,我在程序的每次运行中都会得到不同的结果,这表明在每个 Runnable 任务可以完全迭代它之前,数组列表的内容以某种方式发生了更改。

public static class BatchRunnable implements Runnable {

    private CopyOnWriteArrayList<String> batch;

    BatchRunnable(CopyOnWriteArrayList<String> batch){
        this.batch = batch;
    }

    @Override
    public void run(){
        //iterate over batch and work with String elements
        //make no modifications to batch
    }
}
  • 可运行任务不会对数组列表进行任何修改,它仅迭代列表并使用列表的 String 元素进行处理。

  • CopyOnWriteArrayList 唯一发生更改的地方是在每个新的 Runnable 任务实例化时。

当我传入单个字符串而不是批处理时,我得到了一致且正确的结果,但是当我开始在 String ArrayList 中使用批处理时,我得到了不一致的结果,这表明某些东西正在损害 CopyOnWriteArrayList 批处理的并发性,尽管它是据说是线程安全的。

感谢任何帮助,谢谢!

编辑:这是我的批处理正在构建的地方:

        Runnable worker = null;
        while((line = br.readLine()) != null) {
            recordBatch.add(line);
            if(recordBatch.size() == 100){
                worker = new BatchRunnable(recordBatch);
                executor.execute(worker);
                recordBatch.clear();
            }

        }           
        executor.shutdown();
        executor.awaitTermination(60,TimeUnit.SECONDS);  

最佳答案

查看您的 while 循环:

while((line = br.readLine()) != null) {
        recordBatch.add(line);
        if(recordBatch.size() == 100){
            worker = new BatchRunnable(recordBatch);
            executor.execute(worker);
            recordBatch.clear();
        }

    }  

您正在将引用传递给所有 BatchRunnable 中的相同列表。因此,一旦您在一个位置更改 list,它就会反射(reflect)在所有引用中。因此,一旦您使用 recordBatch.clear() 清除列表,列表中的所有引用都是空的,即使是 BatchRunnable 中的引用也是如此。这就是为什么你得到不一致的结果。

您应该在 BatchRunnable 中传递 recordBatch 列表的副本:

worker = new BatchRunnable(new ArrayList<String>(recordBatch));

关于java - CopyOnWriteArrayList迭代器与多线程不一致?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17803515/

相关文章:

java - Spring JPA - 通过 EmbeddedId 部分查找

multithreading - delphi中如何释放线程

c - 如何继续制作一个可以跟踪另一个软件的功能调用的软件?

java android - 在不同屏幕尺寸的图像背景上调整项目

java - Autowiring 集合

java - 从 uiThread Runnable 内部显示 Toast 消息?

java - Android 线程安全的 SharedPreferences

python - CherryPy 和并发

c++ - 在线程之间共享数据时如何从不变性中获益?

java - 是否可以在不使用 JavaMail api 对端口进行硬编码的情况下连接到邮件服务器,基本上代码应该独立于端口。 ?