Runnable、Callable、Executor、Future、FutureTask關系解讀
阿新 • • 發佈:2017-10-28
兩個 cat util lee exceptio java5 主線程 tin []
[java] view plain copy
在再度溫習Java5的並發編程的知識點時發現,首要的就是把Runnable、Callable、Executor、Future等的關系搞明白,遂有了下述小測試程序,通過這個例子上述三者的關系就一目了然了。
在java5以後,一個可以調度執行的線程單元可以有三種方式定義:
Thread、Runnable、Callable,其中Runnable實現的是void run()方法,Callable實現的是 V call()方法,並且可以返回執行結果,其中Runnable可以提交給Thread來包裝下,直接啟動一個線程來執行,而Callable則一般都是提交給ExecuteService來執行。
簡單來說,Executor就是Runnable和Callable的調度容器,Future就是對於具體的調度任務的執行結果進行查看,最為關鍵的是Future可以檢查對應的任務是否已經完成,也可以阻塞在get方法上一直等待任務返回結果。Runnable和Callable的差別就是Runnable是沒有結果可以返回的,就算是通過Future也看不到任務調度的結果的。
- /**
- * 通過簡單的測試程序來試驗Runnable、Callable通過Executor來調度的時候與Future的關系
- */
- package com.hadoop.thread;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- public class RunnableAndCallable2Future {
- public static void main(String[] args) {
- // 創建一個執行任務的服務
- ExecutorService executor = Executors.newFixedThreadPool(3);
- try {
- //1.Runnable通過Future返回結果為空
- //創建一個Runnable,來調度,等待任務執行完畢,取得返回結果
- Future<?> runnable1 = executor.submit(new Runnable() {
- @Override
- public void run() {
- System.out.println("runnable1 running.");
- }
- });
- System.out.println("Runnable1:" + runnable1.get());
- // 2.Callable通過Future能返回結果
- //提交並執行任務,任務啟動時返回了一個 Future對象,
- // 如果想得到任務執行的結果或者是異常可對這個Future對象進行操作
- Future<String> future1 = executor.submit(new Callable<String>() {
- @Override
- public String call() throws Exception {
- // TODO Auto-generated method stub
- return "result=task1";
- }
- });
- // 獲得任務的結果,如果調用get方法,當前線程會等待任務執行完畢後才往下執行
- System.out.println("task1: " + future1.get());
- //3. 對Callable調用cancel可以對對該任務進行中斷
- //提交並執行任務,任務啟動時返回了一個 Future對象,
- // 如果想得到任務執行的結果或者是異常可對這個Future對象進行操作
- Future<String> future2 = executor.submit(new Callable<String>() {
- @Override
- public String call() throws Exception {
- try {
- while (true) {
- System.out.println("task2 running.");
- Thread.sleep(50);
- }
- } catch (InterruptedException e) {
- System.out.println("Interrupted task2.");
- }
- return "task2=false";
- }
- });
- // 等待5秒後,再停止第二個任務。因為第二個任務進行的是無限循環
- Thread.sleep(10);
- System.out.println("task2 cancel: " + future2.cancel(true));
- // 4.用Callable時拋出異常則Future什麽也取不到了
- // 獲取第三個任務的輸出,因為執行第三個任務會引起異常
- // 所以下面的語句將引起異常的拋出
- Future<String> future3 = executor.submit(new Callable<String>() {
- @Override
- public String call() throws Exception {
- throw new Exception("task3 throw exception!");
- }
- });
- System.out.println("task3: " + future3.get());
- } catch (Exception e) {
- System.out.println(e.toString());
- }
- // 停止任務執行服務
- executor.shutdownNow();
- }
- }
執行結果如下:
[plain] view plain copy- runnable1 running.
- Runnable1:null
- task1: result=task1
- task2 running.
- task2 cancel: true
- Interrupted task2.
- java.util.concurrent.ExecutionException: java.lang.Exception: Bad flag value!
FutureTask則是一個RunnableFuture<V>,即實現了Runnbale又實現了Futrue<V>這兩個接口,另外它還可以包裝Runnable和Callable<V>,所以一般來講是一個符合體了,它可以通過Thread包裝來直接執行,也可以提交給ExecuteService來執行,並且還可以通過v get()返回執行結果,在線程體沒有執行完成的時候,主線程一直阻塞等待,執行完則直接返回結果。
[java] view plain copy
- public class FutureTaskTest {
- /**
- * @param args
- */
- public static void main(String[] args) {
- Callable<String> task = new Callable<String>() {
- public String call() {
- System.out.println("Sleep start.");
- try {
- Thread.sleep(1000 * 10);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("Sleep end.");
- return "time=" + System.currentTimeMillis();
- }
- };
- //直接使用Thread的方式執行
- FutureTask<String> ft = new FutureTask<String>(task);
- Thread t = new Thread(ft);
- t.start();
- try {
- System.out.println("waiting execute result");
- System.out.println("result = " + ft.get());
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ExecutionException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- //使用Executors來執行
- System.out.println("=========");
- FutureTask<String> ft2 = new FutureTask<String>(task);
- Executors.newSingleThreadExecutor().submit(ft2);
- try {
- System.out.println("waiting execute result");
- System.out.println("result = " + ft2.get());
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ExecutionException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
執行結果如下:
[java] view plain copy
- waiting execute result
- Sleep start.
- Sleep end.
- result = time=1370844662537
- =========
- waiting execute result
- Sleep start.
- Sleep end.
- result = time=1370844672542
Runnable、Callable、Executor、Future、FutureTask關系解讀