可以通過其提供的get方法,在FutureTask不同的狀態下,以阻塞或者直接返回的方式或者結果。
FutureTask實現了Future和Runnable接口。以FutureTask是否調用了run方法,可以簡單分爲三種狀態
1. 未啓動。 run方法未執行。
2. 已啓動。 run方法執行。
3. 已完成。 run方法正常執行完畢,或者調用cancel取消,或者run方法執行過程中拋出異常。
強調以上不同狀態的特性,是爲了突出一下這個場景的使用:多線程執行任務,任務只被執行一次。
FutureTask正常執行完成會返回值(不會再次執行),若中斷,正在中斷,或者取消時拋出異常。
看下代碼,落地下:
Class TaskHandler{
// 記錄執行過的任務
private final ConcurrentHashMap<Object,Future<String>> taskCache = new ConcurrentHashMap<Object,Future<String>>// hashet用Collections包裝下也可以用,再根據put的返回,判斷該任務已經存在。
public String execute(final String taskName) throws ExecutionException, InterruptException {
while (true) {
Future<String> future = taskCache.get(taskName);
if(future == null) {
Callable<String> task = new Callable<String>() {
@Override
public String call() throws InterruptedException{
return taskName;
}
};
FutureTask<String> futureTask = new FutureTask<String>(task);
future = taskCache.put(taskName, futureTask);
if(future == null) {
future = futureTask;
futureTask.run();
}
}
try {
future.get();
} catch(CancellationException e) {
// 這個是get方法throw出來的異常 這裏有兩種異常CancellationException ExecutionException 只處理CancellationException,是因爲這個異常是主動取消任務的,我們需要將其從taskCache中去除掉
taskCache.remove(taskName, future);
}
}
}
}
以上代碼有個小細節,這裏指出一下。taskCache.remove(taskName, future),可不可以用taskCache.remove(taskName)?答案是可以的,前者是找到taskName對應的index後,調用future的equal判斷是否是同一個對象,後者通過對taskName指針地址或者hashcode進行判斷是否是同一個對象的。推薦使用第二種remove方法,因爲String重寫了equal和hashcode。