如果我們想要在線程執(zhí)行結(jié)束后做一些事情首量,比如生成報表遭庶,發(fā)送通知郵件或者釋放一些系統(tǒng)資源磕蒲,F(xiàn)utureTask類給于我們最好的支持充尉。
想要實現(xiàn)這種控制方式飘言,我們不能直接把Callable<?>對象直接提交到線程執(zhí)行器中運行,而是要借助FutureTask類驼侠,把需要執(zhí)行的線程類發(fā)送給FutureTask對象姿鸿,然后把FutureTask類發(fā)送給執(zhí)行器去執(zhí)行。
首先創(chuàng)建線程類倒源,實現(xiàn)Callable接口(不能使用Runnable)苛预。休眠一個隨機時間來模擬線程執(zhí)行過程。
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* 創(chuàng)建一個雷ExecutableTask實現(xiàn)Callable<String>接口笋熬。
*
* 延遲一定是堅守執(zhí)行
*
* Created by hadoop on 2016/11/3.
*/
public class ExecutableTask implements Callable<String> {
private String name;
public ExecutableTask(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
long duration = (long)(Math.random() * 10);
System.out.printf("Task: %s will delay %d \n", name, duration);
TimeUnit.SECONDS.sleep(duration);
return "Hello, I am " + name;
}
public String getName() {
return name;
}
}
接下來我們繼承FutureTask類實現(xiàn)自己的ResultTask類热某,并重寫done方法。在done方法中即可定義任務(wù)執(zhí)行完畢的處理邏輯,在這里我們打印線程的一些狀態(tài)昔馋。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* 創(chuàng)建類ResultTask繼承FutureTask<String>類
*
* 重寫done()方法:打印任務(wù)isCancelled()狀態(tài)還是完成狀態(tài)筹吐。
*
* Created by hadoop on 2016/11/3.
*/
public class ResultTask extends FutureTask<String> {
private String name;
public ResultTask(Callable<String> callable) {
super(callable);
this.name = ((ExecutableTask)callable).getName();
}
@Override
protected void done() {
if (isCancelled()) {
System.out.printf("%s: Has been canceled.\n", name);
} else {
System.out.printf("%s: Has been finished.\n", name);
}
}
}
在主線程類中,我們創(chuàng)建5個線程任務(wù)秘遏,因為FutureTask實現(xiàn)了Runnable接口丘薛,所以可以直接提交到執(zhí)行器去運行。主線程休眠5s邦危,然后以此取消5個線程榔袋。最后打印已經(jīng)執(zhí)行完成的任務(wù)的信息。
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by hadoop on 2016/11/3.
*
* 在任務(wù)結(jié)束的時候FutureTask類就會調(diào)用done()方法铡俐。
*
* 創(chuàng)建一個實現(xiàn)Callable接口的ExecutableTask類
* 創(chuàng)建一個階乘FutureTask類的ResultTask類
*
* 然后我們就可以在done方法啊中做出一些資源釋放之類的工作了
*
*/
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
ResultTask[] tasks = new ResultTask[5];
for (int i = 0; i < 5; i++) {
ExecutableTask task = new ExecutableTask("Task" + String.valueOf(i));
tasks[i] = new ResultTask(task);
executor.submit(tasks[i]);
}
TimeUnit.SECONDS.sleep(5);
for (int i = 0; i < 5; i++) {
tasks[i].cancel(true);
}
for (int i = 0; i < 5; i++) {
if (!tasks[i].isCancelled()) {
System.out.println(tasks[i].get());
}
}
executor.shutdown();
}
}
控制臺中你可以看到凰兑,每個線程的休眠時間,以及線程結(jié)束時的狀態(tài)审丘。還有執(zhí)行完成線程的信息吏够。
Task: Task0 will delay 3
Task: Task4 will delay 1
Task: Task3 will delay 5
Task: Task2 will delay 8
Task: Task1 will delay 0
Task1: Has been finished.
Task4: Has been finished.
Task0: Has been finished.
Task2: Has been canceled.
Task3: Has been canceled.
Hello, I am Task0
Hello, I am Task1
Hello, I am Task4