Java Reference
In-Depth Information
In all these cases, the usage is the same: you pass an instance of the Callable interface into the
executor, and it returns a Future instance that is a handle on the result. That Future instance also provides
access to any error that occurred during the processing. This usage has three major advantages over
the Runnable approach done by threads: first, you can return a value from your concurrent processing;
second, your errors are not silently swallowed (assuming you get the result from the Future ); and third, a
thread can only run one Runnable instance, but an executor's thread can run handle multiple Callable
instances. Just like with the Thread 's inline Runnable implementation, though, we can provide our Callable
implementation inline using lambdas. This makes the code much simpler to read.
We can see these advantages in play when we rewrite our kata using the executors. Instead of coming
up with a clever way to divvy up the work evenly, we will simply add all the work to be done into our primary
processing executor. Just like before, that executor will have as many threads as we have processors, and it
will be responsible for the CPU-intensive work. We will hand the I/O intensive work off to another executor,
which will be a single thread. Since the hand-off is cleaner, we can set the I/O intensive thread to be
maximum priority, ensuring that it executes as much as possible: we see again there that lambdas make the
code much more readable, since we can specify the ThreadFactory implementation inline. The code for this
kata is given in Listing 6-3.
Listing 6-3. Using Lambdas to Define ExecutorService Work Instances
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.*;
public class Listing3 {
public static void printPrimes(int maxBitLength) {
ExecutorService executor =
ExecutorService printExecutor = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
return t;
// The resulting work
List<Future<?>> futures = new ArrayList<>(maxBitLength);
for (int i = 0; i < maxBitLength; i++) {
int bitLength = i + 1;
Future<String> stringFuture = executor.submit(() -> {
BigInteger prime = PrimeFactory.ofLength(bitLength);
return prime.toString();
Search WWH ::

Custom Search