Java Reference
In-Depth Information
System.out.println("SideEffect parallel sum done in: " +
measurePerf(ParallelStreams::sideEffectParallelSum, 10_000_000L) + "
msecs" );
You could obtain something like the following:
Result: 5959989000692
Result: 7425264100768
Result: 6827235020033
Result: 7192970417739
Result: 6714157975331
Result: 7497810541907
Result: 6435348440385
Result: 6999349840672
Result: 7435914379978
Result: 7715125932481
SideEffect parallel sum done in: 49 msecs
This time the performance of your method isn't important: the only relevant thing is that each
execution returns a different result, all very distant from the correct value of 50000005000000.
This is caused by the fact that multiple threads are concurrently accessing the accumulator and
in particular executing total += value, which, despite its appearance, isn't an atomic operation.
The origin of the problem is that the method invoked inside the forEach block has the side effect
of changing the mutable state of an object shared among multiple threads. It's mandatory to
avoid these kinds of situations if you want to use parallel Streams without incurring similar bad
surprises.
Now you know that shared mutable state doesn't play well with parallel streams and with
parallel computations in general. We'll come back to this idea of avoiding mutation in chapters
13 and 14 when discussing functional programming in more detail. For now, keep in mind that
avoiding shared mutable state ensures that your parallel Stream will produce the right result.
Next, we'll look at some practical advice you can use to figure out when it's appropriate to use
parallel streams to gain performance.
7.1.4. Using parallel streams effectively
In general it's impossible (and pointless) to try to give any quantitative hint on when to use a
parallel stream because any suggestion like “use a parallel stream only if you have at least one
thousand (or one million or whatever number you want) elements” could be correct for a
 
Search WWH ::




Custom Search