You call LongAccumulator.intValue() , which is documented as:
Returns the current value as int after narrowing the primitive conversion.
and following the link to the get() method, we find out:
Returns the current value. The return value is NOT an atomic snapshot; a call in the absence of simultaneous updates returns an accurate result, but parallel updates that occur during the calculation of the value may not be included.
Thus, although the AtomicReference.updateAndGet operation is thread safe, your simultaneous call to LongAccumulator.intValue() and LongAccumulator.accumulate not. A LongAccumulator designed to perform parallel accumulate operations, followed by retrieving the result after all accumulation operations are complete. Note that even if get() returned the correct snapshot, the fact that the call to intValue() and the subsequent accumulate() are two different, therefore non-atomic, operations made the operation still prone to data racing.
In most cases, if you are trying to manipulate data structures in forEach , you are using the wrong job tool, making the code unnecessarily complex and error prone. As Clayn hinted at the comment , words.parallelStream().max(Comparator.comparingInt(String::length)) will do the job concisely and correctly.
source share