MAKING AN ASYNC-CALL-BASED PARALLEL PROGRAM We might like to take a single-threaded program, and following our design recipe from before, break it into units of work and make it parallel. Part of the recipe suggests breaking it into units of work in the single-threaded program, and then calling these functions/classes/etc. using paralel constructs. Asynchronous calls lend themselves nicely to this process. In particular, make the program perform a series of work units asynchronously, returning futures, and then iterating over the futures at completion-time to extract the unit results and combine them into the final result. The ArrayAverage example illustrates how this can work. To do this, we followed a recipe to extract a single (sequential) method call into one that is asychronous, i.e., might perform work in a separate thread, given below. CONVERT A METHOD CALL INTO AN ASYNC CALL For example, suppose you have a method call to foo() in your program like the following, where foo()'s result is subsequently used elsewhere. T z = o.foo(x,y); ... z.bar(); And you want to execute the call to foo() asynchronously (i.e., in another thread), so that the commands in ... can proceed in parallel. 1. Create a separate class that implements Callable where T is the type of the value returned from the function. The constructor should take the arguments to the function (target, and method arguments) as private fields, and ergo, constructor arguments. The method call() is just the call itself, from above, but returning the result. For our example: public class FooCall implements Callable { private T1 x; private T2 y; private T3 o; public FooCall(T1 x, T2 y, T3 o) { this.x = x; this.y = y; this.o = o; } T call() { return o.foo(x,y); } } (Note that you could make this an anonymous class at the call-site; see below.) 2. Replace the callsite invocation with one the creates an instance of this new class and passes it to an ExecutorService for execution. This will return a Future for a Callable. For the example: ExecutorService executor = Executors.newFixedThreadPool(4); Future z = executor.submit(new FooCall(x,y,o)); 3. Finally, any place that z was used in the old program, expecting it to be of type T, you must replace with a call to the Future.get() method. This call will block until the result is actually available. So, for our example, the line z.bar() becomes z.get().bar() But this doesn't quite cut it. In particular calls to get() could throw an exception. This will be true if the asynchronous call threw an exception, or if the asynchronous task was cancelled for some reason. The book suggests how to deal with this situation; see Sections 5.5.2 and 5.6, and the utility method launderThrowable().