JUC學習筆記(五)
JUC學習筆記(一)https://www.cnblogs.com/lm66/p/15118407.html
JUC學習筆記(二)https://www.cnblogs.com/lm66/p/15118813.html
JUC學習筆記(三)https://www.cnblogs.com/lm66/p/15118976.html
JUC學習筆記(四)https://www.cnblogs.com/lm66/p/15122281.html
1、Callable&Future 介面
1.1、Callable介面
建立執行緒的方法-一種是通過建立 Thread 類,另一種是通過使用 Runnable 建立執行緒。但是,Runnable 缺少的一項功能是,當執行緒終止時(即 run()完成時),我們無法使執行緒返回結果。為了支援此功能,Java 中提供了 Callable 介面。
建立執行緒的第三種方案---Callable 介面
Callable 介面的特點如下
- 為了實現 Runnable,需要實現不返回任何內容的 run()方法,而對於Callable,需要實現在完成時返回結果的 call()方法。
- call()方法可以引發異常,而 run()則不能。
- 為實現 Callable 而必須重寫 call 方法
- 不能直接替換 runnable,因為 Thread 類的構造方法根本沒有 Callable
class MyThread implements Runnable { @Override public void run() { } } class MyThread2 implements Callable<Integer> { @Override public Integer call() throws Exception { return 200; } }
1.2、Future介面
當 call()方法完成時,結果必須儲存在主執行緒已知的物件中,以便主執行緒可以知道該執行緒返回的結果。為此,可以使用 Future 物件。將 Future 視為儲存結果的物件–它可能暫時不儲存結果,但將來會儲存(一旦Callable 返回)。Future 基本上是主執行緒可以跟蹤進度以及其他執行緒的結果的一種方式。要實現此介面,必須重寫 5 種方法,這裡列出了重要的方法,如下:
public boolean cancel(boolean mayInterrupt):用於停止任務。
如果尚未啟動,它將停止任務。如果已啟動,則僅在 mayInterrupt 為 true時才會中斷任務。
public Object get()丟擲 InterruptedException,ExecutionException:用於獲取任務的結果。
如果任務完成,它將立即返回結果,否則將等待任務完成,然後返回結果。
public boolean isDone():如果任務完成,則返回 true,否則返回 false
可以看到 Callable 和 Future 做兩件事-Callable 與 Runnable 類似,因為它封裝了要在另一個執行緒上執行的任務,而 Future 用於儲存從另一個執行緒獲得的結果。實際上,future 也可以與 Runnable 一起使用。
要建立執行緒,需要 Runnable。為了獲得結果,需要 future
1.3、FutrueTask
Java 庫具有具體的 FutureTask 型別,該型別實現 Runnable 和 Future,並方便地將兩種功能組合在一起。 可以通過為其建構函式提供 Callable 來建立FutureTask。然後,將 FutureTask 物件提供給 Thread 的建構函式以建立Thread 物件。因此,間接地使用Callable 建立執行緒。
核心原理:(重點)
在主執行緒中需要執行比較耗時的操作時,但又不想阻塞主執行緒時,可以把這些作業交給 Future 物件在後臺完成
- 當主執行緒將來需要時,就可以通過 Future 物件獲得後臺作業的計算結果或者執行狀態
- 一般 FutureTask 多用於耗時的計算,主執行緒可以在完成自己的任務後,再去獲取結果。
- 僅在計算完成時才能檢索結果;如果計算尚未完成,則阻塞 get 方法 一旦計算完成,就不能再重新開始或取消計算 get 方法而獲取結果只有在計算完成時獲取,否則會一直阻塞直到任務轉入完成狀態,然後會返回結果或者丟擲異常
- get 只計算一次,因此 get 方法放到最後
1.4、使用Callable和Futrue
CallableDemo 案例
public class CallableDemo {
public static void main(String[] args) throws Exception {
Callable<String> callable = () -> {
System.out.println("come in call");
TimeUnit.SECONDS.sleep(3);
return "return val";
};
FutureTask<String> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
System.out.println("continue");
String s = futureTask.get();
System.out.println(s);
System.out.println("over");
}
}
1.5、小結
- 在主執行緒中需要執行比較耗時的操作時,但又不想阻塞主執行緒時,可以把這些作業交給 Future 物件在後臺完成, 當主執行緒將來需要時,就可以通過 Future物件獲得後臺作業的計算結果或者執行狀態
- 一般 FutureTask 多用於耗時的計算,主執行緒可以在完成自己的任務後,再去獲取結果
- 僅在計算完成時才能檢索結果;如果計算尚未完成,則阻塞 get 方法。一旦計算完成,就不能再重新開始或取消計算。get 方法而獲取結果只有在計算完成時獲取,否則會一直阻塞直到任務轉入完成狀態,然後會返回結果或者丟擲異常。
- 只計算一次