This snippet is from JCIP (Brian Goetz) listing 6.15
f.get() throws InterruptedException and ExecutionException. Now, these exceptions are specific to the future correct?
Meaning the specific task represented by the future was interrupted or had an internal exception.
Questions –
-
Why do I need to restore the interrupt using “Thread.currentThread().interrupt()”? , because isnt the interrupt flag for the thread my task ran in? This is a little confusing.
-
Why throw launderThrowable exception? If one of the downloadImage had an issue, shouldnt we just process the other downloaded images intead of throwing from here and thus just “not” processing the remaining futures?
package net.jcip.examples; import java.util.*; import java.util.concurrent.*; import static net.jcip.examples.LaunderThrowable.launderThrowable; /** * Renderer * <p/> * Using CompletionService to render page elements as they become available * * @author Brian Goetz and Tim Peierls */ public abstract class Renderer { private final ExecutorService executor; Renderer(ExecutorService executor) { this.executor = executor; } void renderPage(CharSequence source) { final List<ImageInfo> info = scanForImageInfo(source); CompletionService<ImageData> completionService = new ExecutorCompletionService<ImageData>(executor); for (final ImageInfo imageInfo : info) completionService.submit(new Callable<ImageData>() { public ImageData call() { return imageInfo.downloadImage(); } }); renderText(source); try { for (int t = 0, n = info.size(); t < n; t++) { Future<ImageData> f = completionService.take(); ImageData imageData = f.get(); renderImage(imageData); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { throw launderThrowable(e.getCause()); } } interface ImageData { } interface ImageInfo { ImageData downloadImage(); } abstract void renderText(CharSequence s); abstract List<ImageInfo> scanForImageInfo(CharSequence s); abstract void renderImage(ImageData i); }
The interruption does not necessarily happen on the thread pool’s thread. The interruption is for a point when your current thread is interrupted while you are waiting on the future’s get to complete. For instance, if you made the Future accessible to another part of the program that can cancel the download, then Future.cancel(true) will cause that InterruptedException to occur which you can then clean up the rest of the data. And as Beohemaian mentioned, it is always safe to propogate the interruption.
Thats a good question. I think that was more of a design choice of what he wanted it to do. But you can easily hold onto that error and throw it after the rest complete. Something to think about though, what if its an OutOfMemoryError? Then the launder would be useful to only throw if its an Error and maybe not a RuntimeException.