Skip to content

Commit fcb2fc4

Browse files
committed
Adds new Divide and Conquer Pattern and some fix
1 parent fdb1cb1 commit fcb2fc4

File tree

4 files changed

+156
-6
lines changed

4 files changed

+156
-6
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Concurrency Patterns and features found in Java, through multithreaded programmi
4949
* [Task Convergence](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/task_convergence/TaskConvergence.java)
5050
* [Non-Blocking with Atomics](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/non_blocking)
5151
* [Controlled Concurrent Initialization](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/controlled_initialization/ControlledInitialization.java)
52+
* [Parallel Divide and Conquer](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/divideconquer/)
5253

5354
## About
5455
Patterns and Algorithms inspired by the Java Concurrency in Practice book.

src/main/java/br/com/leonardoz/features/forkjoin/UsingForkJoinFramework.java

-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.concurrent.ForkJoinPool;
88
import java.util.concurrent.RecursiveAction;
99
import java.util.concurrent.RecursiveTask;
10-
import java.util.concurrent.TimeUnit;
1110

1211
/**
1312
*
@@ -202,11 +201,6 @@ public static void main(String[] args) {
202201
RecSumTask task = new RecSumTask(numbers);
203202
BigInteger result = commonPool.invoke(task);
204203
System.out.println("Result is: " + result);
205-
try {
206-
commonPool.awaitTermination(4, TimeUnit.SECONDS);
207-
} catch (InterruptedException e) {
208-
e.printStackTrace();
209-
}
210204
System.out.println("\n\n");
211205
}
212206

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package br.com.leonardoz.patterns.divideconquer;
2+
3+
import java.util.List;
4+
import java.util.concurrent.RecursiveTask;
5+
6+
/*
7+
* Pattern: Parallel Divide and Conquer
8+
*
9+
* Motivations: Some kind of tasks, algorithms or flows can be divided
10+
* into smaller pieces, which are independently resolvable, making them fall
11+
* into the category of divide and conquer computations. Those properties
12+
* allows the execution to be parallel, possible increasing the speed if those
13+
* problems were difficult enough to compensate the cost involved in parallelization.
14+
*
15+
* Intent: Make the execution of some computation that uses the divide and conquer
16+
* approach parallel, in order to increase performance if the problem difficulty is
17+
* enough to overcome the overhead of using threads and coordination. It uses the ForkJoin Framework
18+
* to model those problems.
19+
*
20+
* Applicability: Divide and conquer computations.
21+
*
22+
*/
23+
public class DivideAndConquer {
24+
25+
private final static int THRESHOLD = 10; // Choosing a number to split the computation
26+
27+
28+
public static class Task extends RecursiveTask<Integer> {
29+
30+
private static final long serialVersionUID = 1L;
31+
private List<Integer> somethingToDivideAndConquer;
32+
33+
public Task(List<Integer> somethingToDivideAndConquer) {
34+
this.somethingToDivideAndConquer = somethingToDivideAndConquer;
35+
36+
}
37+
38+
@Override
39+
protected Integer compute() {
40+
int size = somethingToDivideAndConquer.size();
41+
if (size < THRESHOLD) {
42+
// solves directly
43+
return 1;
44+
} else {
45+
// creates tasks, fork and join
46+
return 2;
47+
}
48+
}
49+
50+
}
51+
52+
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package br.com.leonardoz.patterns.divideconquer;
2+
3+
import java.math.BigInteger;
4+
import java.util.List;
5+
import java.util.concurrent.ForkJoinPool;
6+
import java.util.concurrent.RecursiveTask;
7+
import java.util.stream.Collectors;
8+
import java.util.stream.LongStream;
9+
10+
/*
11+
* Pattern: Parallel Divide and Conquer
12+
*
13+
* Example: Parallel Sum
14+
*/
15+
public class ParallelSum extends RecursiveTask<BigInteger> {
16+
17+
private static final long serialVersionUID = 1L;
18+
private final static int THRESHOLD = 10_000; // Choosing a number to split the computation
19+
20+
private List<BigInteger> nums;
21+
22+
public ParallelSum(List<BigInteger> nums) {
23+
this.nums = nums;
24+
}
25+
26+
@Override
27+
protected BigInteger compute() {
28+
int size = nums.size();
29+
if (size < THRESHOLD) {
30+
return sequentialSum(nums);
31+
} else {
32+
ParallelSum x = new ParallelSum(nums.subList(0, size / 2));
33+
ParallelSum y = new ParallelSum(nums.subList(size / 2, size));
34+
x.fork();
35+
y.fork();
36+
BigInteger xResult = x.join();
37+
BigInteger yResult = y.join();
38+
return yResult.add(xResult);
39+
}
40+
}
41+
42+
/*
43+
* Just showing how to use the pattern and some really dummy benchmark. Don't
44+
* take it seriously.
45+
*/
46+
public static void main(String[] args) throws InterruptedException {
47+
List<BigInteger> nums = LongStream.range(0, 10_000_000L).mapToObj(BigInteger::valueOf)
48+
.collect(Collectors.toList());
49+
50+
// Run one then comment and run another
51+
Runnable parallel = () -> {
52+
ForkJoinPool commonPool = ForkJoinPool.commonPool();
53+
BigInteger result = commonPool.invoke(new ParallelSum(nums));
54+
55+
System.out.println("Parallel Result is: " + result);
56+
};
57+
58+
Runnable sequential = () -> {
59+
BigInteger acc = sequentialSum(nums);
60+
61+
System.out.println("Sequential Result is: " + acc);
62+
};
63+
64+
sequential.run();
65+
parallel.run();
66+
67+
Thread.sleep(2000);
68+
69+
System.out.println("#### After some JIT \n\n");
70+
71+
dummyBenchmark(sequential);
72+
dummyBenchmark(parallel);
73+
74+
Thread.sleep(2000);
75+
76+
System.out.println("#### After more JIT \n\n");
77+
78+
dummyBenchmark(sequential);
79+
dummyBenchmark(parallel);
80+
}
81+
82+
private static BigInteger sequentialSum(List<BigInteger> nums) {
83+
BigInteger acc = BigInteger.ZERO;
84+
for (BigInteger value : nums) {
85+
acc = acc.add(value);
86+
}
87+
return acc;
88+
}
89+
90+
static void getHot(Runnable runnable) {
91+
runnable.run();
92+
}
93+
94+
static void dummyBenchmark(Runnable runnable) {
95+
long before = System.currentTimeMillis();
96+
runnable.run();
97+
long after = System.currentTimeMillis();
98+
System.out.println("Executed in: " + (after - before));
99+
System.out.println("######\n");
100+
}
101+
102+
}

0 commit comments

Comments
 (0)