1. 程式人生 > >任務執行(二)

任務執行(二)

    一、序列的頁面渲染器

class SingleThreadRenderer {
	void renderPage(CharSequence source) {
		renderText(source);
		List<ImageData> imageData = new ArrayList<ImageData>();
		for(ImageInfo imageInfo : scanForImageInfo(source)) {
			imageData.add(imageInfo.downloadImage());
		}
		for(ImageData data : imageData) {
			renderImage(data);
		}
	}
}
    二、為了使頁面渲染器實現更高的併發性,首先將渲染過程分解為兩個任務,一個是渲染所有的文字,

另一個是下載所有的影象。

    Callable和Future有助於表示協同任務之間的互動。下面的程式碼中建立了一個Callable來下載所有的影象,

並將其提交到一個ExecutorService這將返回一個描述任務執行情況的Future。當主任務需要影象時,它會

等待Future.get的呼叫結果。如果幸運的話,當開始請求時所有的影象就已經下載完成了,即使沒有,至少

影象的下載任務也已經提交開始了。


    使用Future等待影象下載

class FutureRenderer {
	private final ExecutorService executor = .;
	
	void renderPage(CharSequence source) {
		final List<ImageInfo> imageInfos = scanForImageInfo(source);
		Callable<List<ImageData>> task = new Callable<List<ImageData>> () {
			public List<ImageData> call() {
				List<ImageData> result = new ArrayList<ImageData>();
				for(ImageInfo imageInfo : imageInfos) {
					result.add(imageInfo.downloadImage());
				}
				return result;
			}
		};
		
		Future<List<ImageData>> future = executor.submit(task);
		renderText(source);
		try{
			List<ImageData> imageData = future.get();
			for(ImageData data : imageData) {
				rederImage(data);
			}
		} catch (InterruptedException e) {
			//重新設定執行緒的中斷狀態
			Thread.currentThread().interrupt();
			//由於不需要結束,因此取消任務
			future.cancel(true);
		} catch (ExecutionException e) {
			throw launderThrowable(e.getCause());
		}
	}
}


    三、使用CompletionService實現頁面渲染器

    可以通過CompletionService從兩個方法來提高頁面渲染器的效能:縮短總執行時間以及提高響應性。為每一幅

影象的下載都建立一個獨立任務,並在執行緒池中執行它們,從而將序列的下載過程轉換為並行的過程:這將減少

下載所有影象的總時間。此外,通過從CompletionService中獲取結果以及使每張圖片在下載完成後立刻顯示出來,

能使使用者獲得一個更加動態和更高響應性的使用者介面。

class Renderer {
	private final ExecutorService executor;
	
	Renderer(ExecutorService executor) {
		this.executor = executor;
	}
	
	void renderPage(CharSequence source ) {
		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());
		}
	}
}


通過Future來取消任務

public static void timedRun(Runnable r,long timeout,TimeUnit unit) throws InterruptedException {
	Future<?> task = taskExec.submit(r);
	try{
		task.get(timeout, unit);
	} catch(TimeoutException e) {
		//接下來任務將被取消
	} catch(ExecutionException e) {
		throw launderThrowable(e.getCause());
	} finally {
		task.cancel(true);//如果任務正在執行,將被中斷
	}
}