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

huangapple go评论65阅读模式
英文:

Is it necessary to add synchronized to my code?

问题

以下代码有时会在 ret.forEach(v -> System.out.println(v)); 行处生成 NullPointerException 异常。
我认为我需要使用同步块或 Lock 接口来避免这个错误。
这样正确吗?
请给我一些建议。

List<Integer> ret = new ArrayList<>();
IntStream.range(0, 10).parallel().forEach(i -&gt; {			
    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 -&gt; System.out.println(v));
英文:

the following code sometimes generates NullPointerException Exception at ret.forEach(v -&gt; System.out.println(v)); line.
I think I have to use synchronized block or Lock Interface to avoid this error.
Is it correct?
Please tell me some advice.

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

答案1

得分: 2

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

在使用非线程安全的集合时,出现不应该存在的空值是可能的结果之一。

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

英文:

Basically yes: you modify an ArrayList from multiple threads. ArrayList is not thread-safe, so doing that can cause any number of issues (there is no single problem/exception that will always happen).

Null-values being present when they shouldn't be is one of the possible outcomes of using non-thread collections.

The best way to produce a list from a stream is therefore not to use forEach and explicitly add something to a list, but to use map and collect.

答案2

得分: 1

这里有一些需要评论的事情:

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

  2. 你正在并行地向ArrayList添加元素。ArrayList不是线程安全的,所以不应在这里使用它。参考在Java中选择最佳并发列表

  3. 最后,如果你正在使用streams,最好使用mapcollect。类似于这样的方式:

    IntStream.range(0, 10)
      .parallel()
      .map(i -&gt; do_watever(i))
      .collect(Collectors.toList());;
    
英文:

There are some things here to comment:

  1. You can't use ret before its declaration.

  2. You are adding elements to an ArrayList in parallel. ArrayList is not threadsafe so you shouldn't use it there. Look at Choosing the best concurrency list in Java.

  3. Finally, if you are using streams, its better to use a map and a collect. Something similar to this:

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

huangapple
  • 本文由 发表于 2020年10月9日 17:08:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/64277010.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定