Future和Callable,CompletionService實現並行化
阿新 • • 發佈:2018-12-20
Callable和Future實現並行化
Future表示一個任務的生命週期,並可以判斷是否完成和取消。 介面 方法如下:
- boolean cancel(boolean);取消任務
- V get();獲取結果,阻塞等待
- V get(long, TimeUnit);最大超時等待(時間,時間單位)
- boolean isCancelled();
- boolean isDone(); 如下面程式碼示例:當載入頁面時,非同步並行下載圖片。實現載入文字(CPU密集型)與下載圖片(IO密集型)的並行化,不至於等待圖片的過程中,文字載入不出來:
package com.zxa.parallel;
import com.sun.scenario.effect.ImageData;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @ClassName: parallel
* @Description: //Callable和Future實現並行頁面渲染
* @Author: zhangxin_an
* @CreateDate: 2018/11/7 20:05
*/
public class FutureRenderer {
private final ExecutorService executorService = Executors.newCachedThreadPool();
/**
* @description 載入文字與載入影象並行操作,先渲染文字,在根據載入圖形的執行緒返回值渲染影象
* @method renderPage
* @params [source]
* @return void
* @date: 2018/11/7 20:16
* @author:zhangxin_an
*/
void renderPage(CharSequence source){
//獲取影象資訊(包括url)
final List<ImageInfo> imageInfos = scanForInageInfo(source);
Callable<List<ImageData>> task = new Callable<List<ImageData>>() {
@Override
public List<ImageData> call() throws Exception {
List<ImageData> result = new ArrayList<>();
for (ImageInfo imageInfo : imageInfos){
//下載圖片到本地
result.add(imageInfo.downloadImage());
}
return result;
}
};
Future<List<ImageData>> future = executorService.submit(task);
//渲染文字
renderText(source);
try{
List<ImageData> imageData = future.get();
//執行渲染影象操作...TODO
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
future.cancel(true);
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
private void renderText(CharSequence source) {
}
private List<ImageInfo> scanForInageInfo(CharSequence source) {
return null;
}
}
缺點:必須所有影象載入完才渲染,併發性十分有限。 解決:保留任務關聯的每一個Future,反覆呼叫get(),同時將timeout指定為0,輪詢來判斷任務是否完成。 更好的方法:
CompletionService(完成服務)
CompletionService將Executor和BlockingQueue功能結合在一起。當將Callable任務交給CompletionService時,可以用類似於佇列的take和poll方法來獲取完成的結果,返回值為Future。ExecutorCompletionService為其實現類,並將計算結果委託給Executor. 修改如下:
package com.zxa.parallel;
import com.sun.scenario.effect.ImageData;
import java.util.List;
import java.util.concurrent.*;
/**
* @ClassName: Renderer
* @Description: //CompletionService實現一組任務並行獲取結果
* @Author: zhangxin_an
* @CreateDate: 2018/11/7 20:55
*/
public class Renderer {
private final ExecutorService executorService;
Renderer(ExecutorService executorService){
this.executorService = executorService;
}
void renderPage(CharSequence source){
List<ImageInfo> infos = scanForImageInfo(source);
//建構函式傳入Executor,委託其執行任務
CompletionService<ImageData> completionService = new ExecutorCompletionService<>(executorService);
for(final ImageInfo imageInfo : infos){
completionService.submit(new Callable<ImageData>() {
@Override
public ImageData call() throws Exception {
return imageInfo.downloadImage();
}
});
}
renderText(source);
try {
for(int t = 0, n = infos.size(); t < n; t++ ){
Future<ImageData> future = completionService.take();
ImageData imageData = future.get();
renderImage(imageData);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
private void renderImage(ImageData imageData) {
}
private void renderText(CharSequence source) {
}
private List<ImageInfo> scanForImageInfo(CharSequence source) {
return null;
}
}
多個CompletionService可以共用一個Executor.