CompletionService实际上可以看做是Executor和BlockingQueue的结合体。CompletionService在接收到要执行的任务时,通过类似BlockingQueue的put和take获得任务执行的结果。
CompletionService的一个实现是ExecutorCompletionService,ExecutorCompletionService把具体的计算任务交给Executor完成。
异步下载图片,并实时渲染已下载图片的代码样例,通过将结果加入阻塞队列的方式来绕过异步结果Future.get()的等待问题
1 package net.jcip.examples; 2 3 import java.util.*; 4 import java.util.concurrent.*; 5 import static net.jcip.examples.LaunderThrowable.launderThrowable; 6 7 /** 8 * Renderer 9 * <p/> 10 * Using CompletionService to render page elements as they become available 11 * 12 * @author Brian Goetz and Tim Peierls 13 */ 14 public abstract class Renderer { 15 private final ExecutorService executor; 16 17 Renderer(ExecutorService executor) { 18 this.executor = executor; 19 } 20 21 void renderPage(CharSequence source) { 22 final List<ImageInfo> info = scanForImageInfo(source); 23 CompletionService<ImageData> completionService = 24 new ExecutorCompletionService<ImageData>(executor); 25 for (final ImageInfo imageInfo : info) 26 completionService.submit(new Callable<ImageData>() { 27 public ImageData call() { 28 return imageInfo.downloadImage(); 29 } 30 }); 31 32 renderText(source); 33 34 try { 35 for (int t = 0, n = info.size(); t < n; t++) { 36 Future<ImageData> f = completionService.take(); 37 ImageData imageData = f.get(); 38 renderImage(imageData); 39 } 40 } catch (InterruptedException e) { 41 Thread.currentThread().interrupt(); 42 } catch (ExecutionException e) { 43 throw launderThrowable(e.getCause()); 44 } 45 } 46 47 interface ImageData { 48 } 49 50 interface ImageInfo { 51 ImageData downloadImage(); 52 } 53 54 abstract void renderText(CharSequence s); 55 56 abstract List<ImageInfo> scanForImageInfo(CharSequence s); 57 58 abstract void renderImage(ImageData i); 59 60 }