在ParallelStream中使用java isomicReference线程是否安全?

我使用parallelStream来获取数组中最长的字符串,代码跟随,每次运行时,我得到不同的结果.即使在parallelStream中使用,AtomicReference也认为是线程安全的?但为什么会这样呢?

public static void main(String[] args) {
  AtomicReference<String> longest = new AtomicReference<>();
  LongAccumulator accumulator = new LongAccumulator(Math::max, 0);
  List<String> words = Arrays.asList("him", "he", "thanks", "strings", "congratulations", "platform");
  words.parallelStream().forEach(
          next -> longest.updateAndGet(
                     current -> {
                        String result = next.length() > accumulator.intValue() ? next : current;
                        accumulator.accumulate(next.length());
                        return result;
                     }
                  )
  );
  System.out.println(longest.get());
}

有一段时间,我打印出“祝贺”,有时我打印出“平台”.

您正在调用 LongAccumulator.intValue(),其记录为:

Returns the 07001 as an int after a narrowing primitive conversion.

并遵循linke到get()方法,我们将学习:

Returns the current value. The returned value is NOT an atomic snapshot; invocation in the absence of concurrent updates returns an accurate result, but concurrent updates that occur while the value is being calculated might not be incorporated.

因此,虽然AtomicReference.updateAndGet操作是线程安全的,但并不是LongAccumulator.intValue()和LongAccumulator.accumulate的并发调用. LongAccumulator用于执行并发累积操作,然后在所有累积操作完成后获取结果.请注意,即使get()返回正确的快照,intValue()和后续accumulate()的调用是两个不同的,因此非原子的操作,这使得操作仍然容易发生数据竞争.

在大多数情况下,如果您发现自己试图在forEach中操作数据结构,那么您正在使用错误的工具来完成工作,从而使代码变得不必要地复杂且容易出错.
作为Clayn hinted in a comment,awords.parallelStream().max(Comparator.comparingInt(String :: l ength))将简明扼要地完成工作.

相关文章
相关标签/搜索