考慮以下場景:瀏覽網(wǎng)頁時(shí),瀏覽器了5個(gè)線程下載網(wǎng)頁中的圖片文件,由于圖片大小、網(wǎng)站訪問速度等諸多因素的影響,完成圖片下載的時(shí)間就會有很大的不同。如果先下載完成的圖片就會被先顯示到界面上,反之,后下載的圖片就后顯示。
Java的并發(fā)庫的CompletionService可以滿足這種場景要求。該接口有兩個(gè)重要方法:submit()和take()。submit用于提交一個(gè)runnable或者callable,一般會提交給一個(gè)線程池處理;而take就是取出已經(jīng)執(zhí)行完畢runnable或者callable實(shí)例的Future對象,如果沒有滿足要求的,就等待了。 CompletionService還有一個(gè)對應(yīng)的方法poll,該方法與take類似,只是不會等待,如果沒有滿足要求,就返回null對象。
package concurrent;
import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;
public class TestCompletionService { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService exec = Executors.newFixedThreadPool(10); CompletionService<String> serv = new ExecutorCompletionService<String>(exec);
for (int index = 0; index < 5; index++) { final int NO = index; Callable<String> downImg = new Callable<String>() { public String call() throws Exception { Thread.sleep((long) (Math.random() * 10000)); return "Downloaded Image " + NO; } }; serv.submit(downImg); }
Thread.sleep(1000 * 2); System.out.println("Show web content"); for (int index = 0; index < 5; index++) { Future<String> task = serv.take(); String img = task.get(); System.out.println(img); } System.out.println("End"); // 關(guān)閉線程池 exec.shutdown(); } } |
運(yùn)行結(jié)果:
Show web content
Downloaded Image 1
Downloaded Image 2
Downloaded Image 4
Downloaded Image 0
Downloaded Image 3
End