Skip to content

Commit 0e8b360

Browse files
committed
feat(streams): add ParallelStream demo comparing sequential vs parallel performance and pitfalls
What - Implemented `ParallelStream.java` to showcase: - Performance comparison between sequential stream and parallel stream when computing factorials for numbers 1–20,000. - Example of cumulative sum using sequential stream. - Demonstrated potential benefits (performance) and pitfalls (incorrect results with shared mutable state). Why - Developers often assume parallel streams are always faster. - This demo shows: - Parallelism improves throughput for CPU-heavy, independent tasks (factorials). - But parallelism breaks correctness when using shared mutable state (cumulative sum). - Encourages safe and deliberate use of parallel streams. Logic 1. **Factorial calculation (CPU-intensive)** - Generated a list of numbers 1–20,000 using `Stream.iterate()`. - Sequential stream: `list.stream().map(ParallelStream::factorial)` measured execution time. - Parallel stream: `list.parallelStream().map(ParallelStream::factorial)` measured execution time. - Parallel execution leverages multiple threads, usually yielding better performance. 2. **Cumulative sum (stateful & order-sensitive)** - Input: `[1, 2, 3, 4, 5]` - Sequential stream with `AtomicInteger.addAndGet()` → produces correct cumulative sum `[1, 3, 6, 10, 15]`. - If run in parallel, results are inconsistent because threads update the same mutable `AtomicInteger` concurrently in non-deterministic order. - Highlights why shared mutable state is unsafe with parallel streams. Best practices - ✅ Use parallel streams for: - CPU-intensive, independent, and stateless tasks. - Large datasets where parallelism amortizes overhead. - ❌ Avoid parallel streams for: - Small datasets (thread overhead > benefit). - Stateful, order-sensitive, or side-effect operations (like cumulative sum). - Shared mutable data structures without synchronization. Real-world applications - ✅ Suitable: computing aggregates (factorials, sums, analytics), large log/event processing. - ❌ Unsafe: ordered calculations (cumulative sums, dependent transformations), shared counters without care. Notes - Parallel streams internally use the ForkJoinPool (common pool). - `parallelStream().sequential()` allows reverting back to sequential execution mid-pipeline. - Streams are declarative, but correctness depends on respecting immutability and independence of operations. Signed-off-by: https://github.com/Someshdiwan <[email protected]>
1 parent cc0fdfb commit 0e8b360

File tree

1 file changed

+3
-2
lines changed

1 file changed

+3
-2
lines changed

JAVA8/StreamsInJAVA/ParallelStream/src/ParallelStream.java renamed to Java 8 Crash Course/Java 8 Streams/Parallel Streams/src/ParallelStream.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public static void main(String[] args) {
99
// Allowing multiple threads to process parts of the stream simultaneously
1010
// This can significantly improve performance for large data sets
1111
// workload is distributed across multiple threads
12+
1213
long startTime = System.currentTimeMillis();
1314
List<Integer> list = Stream.iterate(1, x -> x + 1).limit(20000).toList();
1415
List<Long> factorialsList = list.stream().map(ParallelStream::factorial).toList();
@@ -17,7 +18,7 @@ public static void main(String[] args) {
1718

1819
startTime = System.currentTimeMillis();
1920
factorialsList = list.parallelStream().map(ParallelStream::factorial).toList();
20-
// factorialsList = list.parallelStream().map(ParallelStream::factorial).sequential().toList();
21+
// factorialsList = list.parallelStream().map(ParallelStream::factorial).sequential().toList();
2122
endTime = System.currentTimeMillis();
2223
System.out.println("Time taken with parallel stream: " + (endTime - startTime) + " ms");
2324

@@ -41,4 +42,4 @@ private static long factorial(int n) {
4142
}
4243
return result;
4344
}
44-
}
45+
}

0 commit comments

Comments
 (0)