【问题标题】:Is it necessary to add synchronized to my code?是否有必要将同步添加到我的代码中?
【发布时间】:2020-10-09 09:08:59
【问题描述】:

以下代码有时会在ret.forEach(v -> System.out.println(v)); 行生成 NullPointerException 异常。 我想我必须使用同步块或锁定接口来避免这个错误。 这是正确的吗? 请告诉我一些建议。

List<Integer> ret = new ArrayList<>();
IntStream.range(0, 10).parallel().forEach(i -> {            
        if (i % 2 == 0) {
            try {
                System.out.println("stop" + i);
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        ret.add(i);
    });         
    ret.forEach(v -> System.out.println(v));

【问题讨论】:

  • 您在IntStream 中使用后定义ret。是不是打错字了?
  • 对不起,我修改将 List ret 放在第一行,

标签: java parallel-processing synchronized


【解决方案1】:

基本上是的:您从多个线程修改了ArrayList。 ArrayList 不是线程安全的,因此这样做可能会导致任意数量的问题(不会总是发生单个问题/异常)。

在不应该出现的情况下出现空值是使用非线程集合的可能结果之一。

因此,从流中生成列表的最佳方法不是使用forEach 并显式向列表中添加内容,而是使用map 和collect。

【讨论】:

  • 谢谢!你的意思是我应该在我的代码中用 map 或 collection 替换 ArrayList,不是吗?
  • 不,我说的是在Stream 上使用不同的方法:而不是使用forEach 手动构建Stream.collect 的功能,您应该使用Stream.collect。
【解决方案2】:

这里有几点要评论:

  1. 你不能在声明之前使用ret。

  2. 您正在向ArrayList 并行添加元素。 ArrayList 不是线程安全的,所以你不应该在那里使用它。看Choosing the best concurrency list in Java。

  3. 最后,如果您使用streams,最好使用map 和collect。类似的东西:

    IntStream.range(0, 10)
      .parallel()
      .map(i -> do_watever(i))
      .collect(Collectors.toList());; 
    

【讨论】:

  • 谢谢!我会看到这个网址。从线程安全的角度来看,使用你的 3. 很好
猜你喜欢
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
  • 1970-01-01
  • 2017-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多