简体   繁体   English

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

[英]is java AtomicReference thread safe when used within parallelStream?

I used the parallelStream to get the longest string in an array, the code is following, each time it runs, I get different result. 我使用parallelStream获取数组中最长的字符串,代码跟随,每次运行时,我得到不同的结果。 AtomicReference supposes to be thread safe even when used within parallelStream? 即使在parallelStream中使用, AtomicReference认为是线程安全的? But why does this happen? 但为什么会这样呢?

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

for one time, I get “congratulations” printed, and some time I get “platform” printed. 有一段时间,我打印出“祝贺”,有时我打印出“平台”。

You are invoking LongAccumulator.intValue() which is documented as: 您正在调用LongAccumulator.intValue() ,其记录为:

Returns the current value as an int after a narrowing primitive conversion. 在缩小基元转换后,将当前值作为int返回。

and following the linke to the get() method we will learn: 并遵循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. 在没有并发更新的情况下调用会返回准确的结果,但是在计算值时发生的并发更新可能不会合并。

So while the AtomicReference.updateAndGet operation is thread safe, your concurrent invocation of LongAccumulator.intValue() and LongAccumulator.accumulate is not. 因此,虽然AtomicReference.updateAndGet操作是线程安全的,但LongAccumulator.intValue()LongAccumulator.accumulate并发调用。 A LongAccumulator is intended for performing concurrent accumulate operations, followed by fetching the result after all accumulate operations have been finished. LongAccumulator用于执行并发accumulate操作,然后所有累积操作完成获取结果。 Note that even if get() was returning a correct snapshot, the fact that the invocation of intValue() and the subsequent accumulate() are two distinct, hence non-atomic, operations made the operation still prone to data races. 请注意,即使get()返回正确的快照, intValue()和后续accumulate()的调用是两个不同的,因此非原子的操作,这使得操作仍然容易发生数据竞争。

In most cases, if you find yourself trying to manipulate data structures in a forEach , you are using the wrong tool for the job, making the code unnecessarily complicated and error prone. 在大多数情况下,如果您发现自己试图在forEach操作数据结构,那么您正在使用错误的工具来完成工作,从而使代码变得不必要地复杂且容易出错。 As Clayn hinted in a comment , a words.parallelStream().max(Comparator.comparingInt(String::l‌​ength)) will do the job concisely and correct. 正如Clayn 在评论中暗示的那样words.parallelStream().max(Comparator.comparingInt(String::l‌​ength))将简明扼要地完成工作。

Actually i was writing about the issue which @Holger mentioned already, i was a bit late, but i am writing this anyway as a proof of @Holger's answer . 实际上我正在写关于@Holger已经提到过的问题,我有点迟了,但无论如何我写这篇文章是为了证明@Holger的答案 You can use AtomicReference 's accumulator; 你可以使用AtomicReference的累加器;

Here is the code : 这是代码:

public static void main(String[] args) {
    AtomicReference < String > longest = new AtomicReference < > ();
    List < String > words = Arrays.asList("him", "he", "thanks", "strings", "congratulations", "platform");

    words.parallelStream().forEach(next - > {
        longest.accumulateAndGet(next, (a, b) - >
            a != null && a.length() > b.length() ? a : b
        );
    });

    System.out.println(longest.get());
}

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

相关问题 Java中的AtomicReference - 在线程安全环境中设置引用所必需的? - AtomicReference in Java - necessary for setting a reference in a thread-safe environment? 什么时候在 Java 中使用 AtomicReference? - When to use AtomicReference in Java? 直接分配易失性可变线程安全吗? 像AtomicReference一样安全吗? - Is a direct assignment of a volatile variable thread safe? As safe as an AtomicReference? 使用parallelstream()在Java 8中填充Map是否安全 - Is it safe to use parallelstream() to populate a Map in Java 8 当setName为java线程时,这是否安全 - Is that safe when setName for java thread 何时使用AtomicReference(Java)? 真的有必要吗? - When to use AtomicReference (Java)? Is it really necessary? 可以以线程安全的方式安全地增加BigInteger,也许使用AtomicReference,没有锁定? - Possible to safely increment BigInteger in a thread safe way, perhaps with AtomicReference, w/o locking? 在Java中,是Collections.sort()线程安全使用的Comparator吗? - In Java, is a Comparator used in Collections.sort() thread safe? 是否有 Java parallelstream 的可用替代方案仍然并行运行线程 - Is there any available Alternative of Java parallelstream that still runs thread in parallel 并行流中HashSet的线程安全性 - Thread safety of HashSet in parallelStream
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM