創建線程有哪幾種方式
- 繼承Thread類(Thread類也是實現Runnable接口);
public
class Thread implements Runnable {
- 實現Runnable接口;
- 通過線程池創建線程池;
- 實現Callable接口與ExecutorService結合使用
因爲Java的類是單繼承,接口可以多實現。所以在創建子任務的時候,更多的是選擇實現接口。線程池的出現爲了讓線程可以很好的複用,減少系統開銷(線程的啓動、銷燬等過程是比較複雜的),同時也統一把線程管理起來。
Runnable不足?
現Runnable接口中的run()方法:
public abstract void run();
通過源碼中的run方法可以看出,run方法沒有返回值。如果我們需要接受子線程返回結果,此時該接口已經不滿足我們的需求了。那麼怎麼接受子線程返回的結果呢?此時就需要通過Callable接口創建線程了。同樣的先看看過Callable接口中的方法定義
Callable接口中的call()方法
V call() throws Exception;
和run()對比,可以看出該方法支持返回值,支持向上拋出異常。
Callable接口的簡單實例
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(new Task());//submit結果
String result = future.get();//取出子線程運行結果
System.out.println("子任務的執行結果:"+result);//子任務的執行結果:1995-01-01
executorService.shutdown();
}
private static class Task implements Callable<String> {
@Override
public String call() throws Exception {
return "1995-01-01";
}
}
FutureTask獲取結果
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
//通過Callable實例構建FutureTask實例
FutureTask<String> futureTask = new FutureTask<>(new Task());
//提交任務到線程池
executorService.execute(futureTask);
//取出子線程運行結果
String result = futureTask.get();
System.out.println("子任務的執行結果:" + result);//子任務的執行結果:1995-01-02
}
private static class Task implements Callable<String> {
@Override
public String call() throws Exception {
return "1995-01-02";
}
}
Future接口中方法
其實根據命名,已經可以推測出這些方法的作用了,下面主要記錄一些注意點
- get():獲取Callable接口返回的結果,假設主線程調用了get()方法,但是此時子線程還沒有執行完畢(即還沒有返回結果),此時主線程會被阻塞,知道call()方法返回了結果。
- get(long timeout, TimeUnit unit):在get()的基礎上加上超時時間;
- isDone():判斷子線程是否執行完畢;
- cancel(boolean mayInterruptIfRunning):取消線程
取消線程坑時可能遇到的幾種情況
1.線程還沒有執行:返回true
2.線程已經執行完畢或者取消了,返回false;
3.線程已經開始執行了,此時根據設置的mayInterruptIfRunning來判斷是否直接取消任務。mayInterruptIfRunning爲ture適用於子任務有邏輯處理中斷。false適用於子線程沒有能力處理中斷;需求是需要等待已經開始的線程執行完畢。
FutureTask
FutureTask:實現了Runnable和Future接口,表示異步計算的結果。