是否有必要在我的代码中添加 synchronized?

Is it necessary to add synchronized to my code?

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

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));

基本上是:您从多个线程修改 ArrayListArrayList 不是 thread-safe,所以这样做会导致 任何数量的 问题(没有一个 problem/exception 会一直发生)。

Null-values 在不应该出现的时候出现是使用 non-thread 集合的可能结果之一。

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

这里有些东西要评论:

  1. 声明前不能使用ret

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

  3. 最后,如果你使用streams,最好使用mapcollect。类似于此:

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