繁体   English   中英

Collection.stream()是否具有内部同步?

Does Collection.stream() have internal synchronization?

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

当一个HashMap实例被多个Thread读取和写入时,我一直在尝试重现(并解决)一个ConcurrentModificationException

免责声明:我知道HashMap不是线程安全的。

在以下代码中:

import java.util.*;

public class MyClass {

    public static void main(String args[]) throws Exception {
        java.util.Map<String, Integer> oops = new java.util.HashMap<>();
        oops.put("1", 1);
        oops.put("2", 2);
        oops.put("3", 3);

        Runnable read = () -> {
            System.out.println("Entered read thread");

            /*
             * ConcurrentModificationException possibly occurs
             *
            for (int i = 0; i < 100; i++) {
                List<Integer> numbers = new ArrayList<>();
                numbers.addAll(oops.values());
                System.out.println("Size " + numbers.size());
            }
            */

            for (int i = 0; i < 100; i++) {
                List<Integer> numbers = new ArrayList<>();
                numbers.addAll(oops.values()
                        .stream()
                        .collect(java.util.stream.Collectors.toList()));
                System.out.println("Size " + numbers.size());
            }
        };

        Runnable write = () -> {
            System.out.println("Entered write thread");
            for (int i = 0; i < 100; i++) {
                System.out.println("Put " + i);
                oops.put(Integer.toString(i), i);
            }
        };

        Thread writeThread = new Thread(write, "write-thread");
        Thread readThread = new Thread(read, "read-thread");

        readThread.start();
        writeThread.start();

        readThread.join();
        writeThread.join();
    }
}

基本上,我创建了两个线程:一个继续将元素放入HashMap ,另一个是在HashMap.values()上迭代。

read线程中,如果我使用numbers.addAll(oops.values()) ,则随机发生ConcurrentModificationException 虽然线条按预期随机打印。

但是,如果我切换到numbers.addAll(oops.values().stream().. ,我没有得到任何错误。但是,我观察到一个奇怪的现象。 read线程的所有行都打印在行后面write线程打印。

我的问题是, Collection.stream()有不同的内部同步?

更新

使用JDoodle https://www.jdoodle.com/a/IYy ,似乎在JDK9和JDK10上,我将按预期获得ConcurrentModificationException

谢谢!

3 个回复

我能够在Java 8上使用流获取ConcurrentModificationException ,但代码中有一些更改:增加的迭代次数和添加的元素数量,以便在100到10000的单独线程中映射。还添加了CyclicBarrier以便读取器和写入器线程中的循环或多或少同时开始。 我还检查了Hashmap.values()的spliterator的源代码,如果对map进行了一些修改,它会抛出ConcurrentModificationException

if (m.modCount != mc) //modCount is number of modifications mc is expected modifications count which is stored before trying to fetch next element
                throw new ConcurrentModificationException();

你所看到的绝对偶然; 请记住内部System.out.println执行synchronzied ; 因此可能会以某种方式使结果看起来像按顺序出现。

我没有深入研究你的代码 - 因为分析为什么HashMap ,它不是线程安全的,是错过表现的,这很可能是徒劳的; 如您所知,它被记录为非线程安全的。

关于那个ConcurrentModificationException ,该文档是特定的,它将尝试最好的赔率抛出; 所以它或者java-8在这一点上都比较弱,或者这也是偶然的。

我快速查看了Java 8的源代码,它确实抛出了ConcurrentModificationException HashMapvalues()方法返回AbstractCollection的子类,其spliterator()方法返回一个ValueSpliterator ,它抛出ConcurrentModificationException

有关信息, Collection.stream()使用spliterator遍历或分区源的元素。

1 Collection.stream() 的实现

我已经在 J​​DK 1.8 上工作了几天,在那里我遇到了一些与此类似的代码: 现在,对于使用流 ( java.util.stream ) 的人来说可能看起来简单而干净,但我找不到实现java.util.Collection.stream()方法的实际类。 当我说list.stream()时, ...

2 Collection.toArray() 与 Collection.stream().toArray()

考虑以下代码: 在我看来,使用流要简单得多。 因此,我测试了每个的速度。 结果是使用流大约慢了四倍。 在我的机器上,816 毫秒(流)与 187 毫秒(无流)。 我还尝试切换时序语句(在 myArray1 之前的 myArray2),这对结果没有太大影响。 为什么这么慢? 创建Stream ...

3 如何避免嵌套的Collection.stream()调用?

假设我们有以下Map 具有以下内容: 与该流API的工具,对于每对类型的[City ; Person] [City ; Person] ,我想应用一些操作,比如说打印: 可能的(但不是很整洁)的解决方案是: 我们如何通过创建对其他Stream / Collect ...

5 Java 8 Streams:如何调用Collection.stream()方法并检索具有不同字段的多个聚合值的数组

我将从Java 8中的Stream API开始。 这是我使用的Person对象: 这是我的代码,它初始化一个对象列表Person,它获取由特定名字过滤的对象数,最大年龄和最小高度,平均权重,最后创建一个包含这些值的对象数组: 是否可以单独调用stream()方法并直接返回对 ...

10 具有昂贵操作的Collection上的Java同步

我有一个列表,我在我的函数doMapOperation同步命名的synchronizedMap 。 在这个函数中,我需要在地图中添加/删除项目并对这些对象执行昂贵的操作。 我知道我不想在同步块中调用昂贵的操作,但我不知道在执行这些操作时如何确保映射处于一致状态。 这样做的正确方法是什么? ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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