Java: splitting work across a thread pool
Divide a sum into chunks, run them on an ExecutorService, and combine the Future results.
import java.util.*;
import java.util.concurrent.*;
class Main {
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(4);
List<Future<Long>> parts = new ArrayList<>();
for (int start = 1; start <= 1000; start += 250) {
final int from = start;
parts.add(pool.submit(() -> {
long sum = 0;
for (int n = from; n < from + 250; n++) {
sum += (long) n * n;
}
return sum;
}));
}
long total = 0;
for (Future<Long> part : parts) {
total += part.get();
}
pool.shutdown();
System.out.println("sum of squares 1..1000 = " + total);
}
}sum of squares 1..1000 = 333833500
Explanation
Data parallelism splits one large job into independent pieces that run at the same time and then combines the results. In Java, an ExecutorService manages a pool of worker threads. submit takes a task and returns a Future, which is a handle for a result that will exist later.
The program sums the squares of 1 to 1000 in four chunks of 250. Each task returns its partial sum, and calling get on each Future waits for that result. Because the chunks do not share mutable state, no locks are needed. shutdown lets the pool stop once the tasks are done.
Explore the dry run
import java.util.*;import java.util.concurrent.*; class Main { public static void main(String[] args) throws Exception { ExecutorService pool = Executors.newFixedThreadPool(4); List<Future<Long>> parts = new ArrayList<>(); for (int start = 1; start <= 1000; start += 250) { final int from = start; parts.add(pool.submit(() -> { long sum = 0; for (int n = from; n < from + 250; n++) { sum += (long) n * n; } return sum; })); } long total = 0; for (Future<Long> part : parts) { total += part.get(); } pool.shutdown(); System.out.println("sum of squares 1..1000 = " + total); }}Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| Create a pool of four worker threads. | pool size = 4 | — | |
| Each loop pass submits one chunk of 250 numbers and keeps its Future. | 4 tasks submitted | — | |
| get waits until that chunk is finished, then adds its partial sum. | partial sums are added in order | — | |
| The result matches the formula n(n+1)(2n+1)/6. | total = 333833500 | sum of squares 1..1000 = 333833500 |
Cost and common mistakes
O(n) total work; with p threads and equal chunks the ideal time is O(n / p) plus coordination overhead.
- Forgetting shutdown leaves non-daemon worker threads alive, so the program may never exit.
- Splitting work too finely makes task overhead larger than the work itself.
- get rethrows task failures as ExecutionException, so handle it in real code.
Try it yourself
What happens if the pool has one thread?
Reveal answer and reasoning
The tasks run one after another and the answer is identical, so there is no speed-up but no change in correctness.