Java線程—-Runnable和Callable的區別和聯系


Java 提供了三種創建線程的方法


1.繼承Thread接口

 1 public class Thread2Thread {
 2     public static void main(String[] args) {
 3         new MyThread1().start();
 4         new Thread(new MyThread1(), "線程2").start();
 5     }
 6 }
 7 
 8 /**
 9  * 通過繼承Thread類
10  */
11 class MyThread1 extends Thread {
12     /**
13      * 重寫run方法
14      */
15     @Override
16     public void run() {
17         // TODO Auto-generated method stub
18         super.run();
19     }
20 }
通過繼承Thread類

2.實現Runnable接口

 1 package com.testthread.demo4;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 
 5 import static java.util.concurrent.Executors.*;
 6 
 7 public class Thread2Runnable {
 8 
 9     public static void main(String[] args) {
10 
11         //case1:通過實現Runnable接口,來實現run方法的具體邏輯
12         new Thread(new MyThread2(), "線程1").start();
13         //case2:匿名內部類
14         new Thread(new Runnable() {
15             @Override
16             public void run() {
17                 // TODO Auto-generated method stub
18 
19             }
20         }, "線程2").start();
21 
22         //其實case1和case2的本質是一樣的
23         
24         //case3:作為線程任務提交給線程池,通過線程池維護的工作者線程來執行。
25         ExecutorService executor = newCachedThreadPool();
26         MyThread2 myThread2 = new MyThread2();
27         executor.execute(myThread2);
28         executor.shutdown();
29     }
30 }
31 
32 /**
33  * 實現Runnable接口的線程類
34  */
35 class MyThread2 implements Runnable {
36 
37     /**
38      * 重寫run方法
39      */
40     @Override
41     public void run() {
42         // TODO Auto-generated method stub
43     }
44 }
實現Runnable接口

3.通過Callable和Future創建線程

 1 import java.util.concurrent.Callable;
 2 import java.util.concurrent.FutureTask;
 3 
 4 public class Thread2Callable {
 5     public static void main(String[] args) {
 6         //創建 Callable 實現類的實例
 7         MyCallable myCallable = new MyCallable();
 8         //使用 FutureTask 類來包裝 Callable 對象,該 FutureTask 對象封裝了該 Callable 對象的 call() 方法的返回值
 9         FutureTask<String> futureTask = new FutureTask<String>(myCallable);
10         String res = null;
11         try {
12             //使用 FutureTask 對象作為 Thread 對象的 target 創建並啟動新線程
13             //沒這句,下句代碼獲取不到結果,會一直等待執行結果
14             new Thread(futureTask,"線程1").start();
15             //調用 FutureTask 對象的 get() 方法來獲得子線程執行結束后的返回值
16             res = futureTask.get();
17         } catch (Exception e) {
18             e.printStackTrace();
19         }
20         System.out.println(res);
21     }
22 }
23 /**
24  * 創建 Callable 接口的實現類,並實現 call() 方法
25  */
26 class MyCallable implements Callable<String> {
27 
28     /**
29      * 該 call() 方法將作為線程執行體,並且有返回值
30      */
31     @Override
32     public String call() throws Exception {
33         return "success";
34     }
35 }
通過Callable和Future創建線程

 

Runnable和Callable的區別和聯系

接口定義

  Runnable  

其中Runnable應該是我們最熟悉的接口,它只有一個run()函數,用於將耗時操作寫在其中,該函數沒有返回值。然后使用某個線程去執行該runnable即可實現多線程,Thread類在調用start()函數后就是執行的是Runnable的run()函數。

Runnable的聲明如下 :

1 public interface Runnable {
2     /*
3      * @see     java.lang.Thread#run()
4      */
5     public abstract void run();
6 }
Runnable

  #Callable

Callable與Runnable的功能大致相似,Callable中有一個call()函數,但是call()函數有返回值,而Runnable的run()函數不能將結果返回給客戶程序。

Callable的聲明如下 :

1 public interface Callable<V> {
2     /**
3      * Computes a result, or throws an exception if unable to do so.
4      *
5      * @return computed result
6      * @throws Exception if unable to compute a result
7      */
8     V call() throws Exception;
9 }
View Code

 

  #Future

Executor就是Runnable和Callable的調度容器,Future就是對於具體的Runnable或者Callable任務的執行結果進行
取消、查詢是否完成、獲取結果、設置結果操作。get方法會阻塞,直到任務返回結果(Future簡介)。

Future聲明如下 :

 1 public interface Future<V> {
 2  
 3     /**
 4      * Attempts to cancel execution of this task.  This attempt will
 5      * fail if the task has already completed, has already been cancelled,
 6      * or could not be cancelled for some other reason. If successful,
 7      * and this task has not started when <tt>cancel</tt> is called,
 8      * this task should never run.  If the task has already started,
 9      * then the <tt>mayInterruptIfRunning</tt> parameter determines
10      * whether the thread executing this task should be interrupted in
11      * an attempt to stop the task.
12      */
13     boolean cancel(boolean mayInterruptIfRunning);
14  
15     /**
16      * Returns <tt>true</tt> if this task was cancelled before it completed
17      * normally.
18      */
19     boolean isCancelled();
20  
21     /**
22      * Returns <tt>true</tt> if this task completed.
23      *
24      */
25     boolean isDone();
26  
27     /**
28      * Waits if necessary for the computation to complete, and then
29      * retrieves its result.
30      *
31      * @return the computed result
32      */
33     V get() throws InterruptedException, ExecutionException;
34  
35     /**
36      * Waits if necessary for at most the given time for the computation
37      * to complete, and then retrieves its result, if available.
38      *
39      * @param timeout the maximum time to wait
40      * @param unit the time unit of the timeout argument
41      * @return the computed result
42      */
43     V get(long timeout, TimeUnit unit)
44         throws InterruptedException, ExecutionException, TimeoutException;
45 }
Future

#FutureTask(很有用)

  FutureTask是一個RunnableFuture<V>  

1 public class FutureTask<V> implements RunnableFuture<V>
FutureTask

 RunnableFuture實現了Runnbale又實現了Futrue<V>這兩個接口

1 public interface RunnableFuture<V> extends Runnable, Future<V> {
2     /**
3      * Sets this Future to the result of its computation
4      * unless it has been cancelled.
5      */
6     void run();
7 }
RunnableFuture

另外FutureTaslk還可以包裝Runnable和Callable<V>, 由構造函數注入依賴。

 1     public FutureTask(Callable<V> callable) {
 2         if (callable == null)
 3             throw new NullPointerException();
 4         this.callable = callable;
 5         this.state = NEW;       // ensure visibility of callable
 6     }
 7  
 8     public FutureTask(Runnable runnable, V result) {
 9         this.callable = Executors.callable(runnable, result);
10         this.state = NEW;       // ensure visibility of callable
11     }
FutureTask(callable)

上面代碼塊可以看出:Runnable注入會被Executors.callable()函數轉換為Callable類型,即FutureTask最終都是執行Callable類型的任務。

該適配函數的實現如下 :

1     public static <T> Callable<T> callable(Runnable task, T result) {
2         if (task == null)
3             throw new NullPointerException();
4         return new RunnableAdapter<T>(task, result);
5     }
callable

RunnableAdapter適配器

 1     /**
 2      * A callable that runs given task and returns given result
 3      */
 4     static final class RunnableAdapter<T> implements Callable<T> {
 5         final Runnable task;
 6         final T result;
 7         RunnableAdapter(Runnable task, T result) {
 8             this.task = task;
 9             this.result = result;
10         }
11         public T call() {
12             task.run();
13             return result;
14         }
15     }
RunnableAdapter
FutureTask實現Runnable,所以能通過Thread包裝執行,

FutureTask實現Runnable,所以能通過提交給ExcecuteService來執行

注:ExecuteService:創建線程池實例對象,其中有submit(Runnable)、submit(Callable)方法

ExecturService:https://blog.csdn.net/suifeng3051/article/details/49443835

還可以直接通過get()函數獲取執行結果,該函數會阻塞,直到結果返回。

因此FutureTask是Future也是Runnable,又是包裝了的Callable( 如果是Runnable最終也會被轉換為Callable )。

 

相同點

1 都是接口
2 都可以編寫多線程程序
3 都采用Thread.start()啟動線程

 不同點

1  Callable規定的方法是call(),而Runnable規定的方法是run(). 
2  Callable的任務執行后可返回值,而Runnable的任務是不能返回值的。  
3   call()方法可拋出異常,而run()方法是不能拋出異常的。--run()方法異常只能在內部消化,不能往上繼續拋
4   運行Callable任務可拿到一個Future對象, Future表示異步計算的結果。 
5   它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。 
6   通過Future對象可了解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。 
7  Callable是類似於Runnable的接口,實現Callable接口的類和實現Runnable的類都是可被其它線程執行的任務。 
注:Callalbe接口支持返回執行結果,需要調用FutureTask.get()得到,此方法會阻塞主進程的繼續往下執行,如果不調用不會阻塞。

 示例:

 1 package com.xzf.callable;
 2  
 3 import java.util.concurrent.Callable;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6 import java.util.concurrent.Future;
 7 import java.util.concurrent.FutureTask;
 8  
 9 public class RunnableFutureTask {
10     static ExecutorService executorService = Executors.newSingleThreadExecutor();    //創建一個單線程執行器
11     public static void main(String[] args) {
12         runnableDemo();    
13         futureDemo();
14     }
15     /**
16      * new Thread(Runnable arg0).start(); 用Thread()方法開啟一個新線程
17      * runnable, 無返回值
18      */
19     static void runnableDemo() {
20         new Thread(new Runnable() {                
21             public void run() {
22                 System.out.println("runnable demo:" + fibc(20));    //有值
23             }
24             
25         }).start();
26     }
27     /**
28      * Runnable實現的是void run()方法,無返回值
29      * Callable實現的是 V call()方法,並且可以返回執行結果
30      * Runnable可以提交給Thread,在包裝下直接啟動一個線程來執行
31      * Callable一般都是提交給ExecuteService來執行
32      */ 
33      
34     static void futureDemo() {
35         try {
36             Future<?> result1 = executorService.submit(new Runnable() {
37                 public void run() {
38                     fibc(20);
39                 }
40             });
41             System.out.println("future result from runnable:"+result1.get());    //run()無返回值所以為空,result1.get()方法會阻塞
42             Future<Integer> result2 = executorService.submit(new Callable<Integer>()     {
43                 public Integer call() throws Exception {
44                     return fibc(20);    
45                 }
46             });
47             System.out.println("future result from callable:"+result2.get());    //call()有返回值,result2.get()方法會阻塞
48             FutureTask<Integer> result3 = new FutureTask<Integer>(new Callable<Integer>() {
49                 public Integer call() throws Exception {
50                     return fibc(20);
51                 }
52             });
53             executorService.submit(result3);    
54             System.out.println("future result from FutureTask:" + result3.get());    //call()有返回值,result3.get()方法會阻塞
55             
56             /*因為FutureTask實現了Runnable,因此它既可以通過Thread包裝來直接執行,也可以提交給ExecuteService來執行*/
57             FutureTask<Integer> result4 = new FutureTask<Integer>(new Runnable() {
58                 public void run() {
59                     fibc(20);
60                 }
61             },fibc(20));    
62             executorService.submit(result4);
63             System.out.println("future result from executeService FutureTask :" + result4.get());    //call()有返回值,result3.get()方法會阻塞
64             //這里解釋一下什么FutureTask實現了Runnable結果不為null,這就用到FutureTask對Runnable的包裝,所以Runnable注入會被Executors.callable()函數轉換成Callable類型
65  
66             FutureTask<Integer> result5 = new FutureTask<Integer>(new Runnable() {
67                 public void run() {
68                     fibc(20);
69                 }
70             },fibc(20));
71             new Thread(result5).start();
72             System.out.println("future result from Thread FutureTask :" + result5.get());    //call()有返回值,result5.get()方法會阻塞
73             
74         } catch (Exception e) {
75             e.printStackTrace();
76         }finally {
77             executorService.shutdown();
78         }
79     }
80     static int fibc(int num) {
81         if (num==0) {
82             return 0;
83         }
84         if (num==1) {
85             return 1;
86         }
87         return fibc(num-1) + fibc(num-2);
88     }
89 }
示例1

運行結果:

1 runnable demo:6765
2 future result from runnable:null
3 future result from callable:6765
4 future result from FutureTask:6765
5 future result from executeService FutureTask :6765
6 future result from Thread FutureTask :6765
運行結果1
 1 package com.testthread.test;
 2 
 3 import java.util.concurrent.*;
 4 import java.util.Date;
 5 import java.util.List;
 6 import java.util.ArrayList;
 7 
 8 public class Test implements Callable<Object> {
 9     private String taskNum;
10 
11     Test(String taskNum) {
12         this.taskNum = taskNum;
13     }
14 
15     public static void main(String[] args) {
16         System.out.println("----程序開始運行----");
17         Date date1 = new Date();
18         int taskSize = 5; // 創建一個線程池
19         ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 創建多個有返回值的任務
20         List<Future> list = new ArrayList<Future>();
21         try {
22             for (int i = 0; i < taskSize; i++) {
23                 Callable c = new Test(i + " "); // 執行任務並獲取Future對象
24                 Future f = pool.submit(c);
25                 list.add(f);
26             }
27             // 獲取所有並發任務的運行結果
28             for (Future f : list) {
29                 // 從Future對象上獲取任務的返回值,並輸出到控制台
30                 System.out.println(">>>" + f.get().toString());
31             }
32         } catch (InterruptedException e) {
33             e.printStackTrace();
34         } catch (ExecutionException e) {
35             e.printStackTrace();
36         } finally {// 關閉線程池
37             pool.shutdown();
38         }
39         Date date2 = new Date();
40         System.out.println("----程序結束運行----,程序運行時間【" + (date2.getTime() - date1.getTime()) + "毫秒】");
41     }
42 
43     @Override
44     public Object call() throws Exception {
45         System.out.println(">>>" + taskNum + "任務啟動");
46         Date dateTmp1 = new Date();
47         Thread.sleep(1000);
48         Date dateTmp2 = new Date();
49         long time = dateTmp2.getTime() - dateTmp1.getTime();
50         System.out.println(">>>" + taskNum + "任務終止");
51         return taskNum + "任務返回運行結果,當前任務時間【" + time + "毫秒】";
52     }
53 }
示例2
 1 ----程序開始運行----
 2 >>>1 任務啟動
 3 >>>0 任務啟動
 4 >>>3 任務啟動
 5 >>>2 任務啟動
 6 >>>4 任務啟動
 7 >>>1 任務終止
 8 >>>3 任務終止
 9 >>>0 任務終止
10 >>>0 任務返回運行結果,當前任務時間【1029毫秒】
11 >>>2 任務終止
12 >>>1 任務返回運行結果,當前任務時間【1029毫秒】
13 >>>2 任務返回運行結果,當前任務時間【1030毫秒】
14 >>>3 任務返回運行結果,當前任務時間【1030毫秒】
15 >>>4 任務終止
16 >>>4 任務返回運行結果,當前任務時間【1030毫秒】
17 ----程序結束運行----,程序運行時間【1146毫秒】
示例2結果
 1 package com.testthread.test;
 2 
 3 import java.util.ArrayList;
 4 import java.util.HashMap;
 5 import java.util.List;
 6 import java.util.Map;
 7 import java.util.concurrent.Callable;
 8 import java.util.concurrent.ExecutionException;
 9 import java.util.concurrent.ExecutorService;
10 import java.util.concurrent.FutureTask;
11 
12 import static java.util.concurrent.Executors.newFixedThreadPool;
13 
14 public class Test2 {
15 
16     public static void main(String[] args) {
17         Map<String, Object> resultMap = new HashMap<>();
18         int count = 10;
19         ExecutorService executorService = newFixedThreadPool(10);
20         long start = System.currentTimeMillis();
21         try {
22             List<FutureTask> list = new ArrayList();
23             for (int i = 0; i < count; i++) {
24                 FutureTask<Map<String, Object>> result = new FutureTask<Map<String, Object>>(myCall(i + ""));
25                 executorService.submit(result);
26                 list.add(result);
27             }
28             for (int i = 0; i < count; i++) {
29                 Map<String, Object> resultMapShow = (Map<String, Object>) list.get(i).get();
30                 System.out.println("resultMapShow = " + resultMapShow);
31                 Map<String, Object> body = (Map<String, Object>) resultMapShow.get("body");
32                 resultMap.put("aa" + i, body.get("aa"));
33             }
34             System.out.println("====>took:" + (System.currentTimeMillis() - start));
35 
36         } catch (InterruptedException e) {
37             e.printStackTrace();
38         } catch (ExecutionException e) {
39             e.printStackTrace();
40         } finally {
41             executorService.shutdown();
42         }
43         System.out.println("resultMap = " + resultMap);
44         System.out.println("==>took:" + (System.currentTimeMillis() - start));
45     }
46 
47 
48     public static Callable<Map<String, Object>> myCall(String taskId) {
49         Callable<Map<String, Object>> callable = new Callable<Map<String, Object>>() {
50             @Override
51             public Map<String, Object> call() throws Exception {
52                 return queryMethod(taskId);
53             }
54         };
55         return callable;
56     }
57 
58     private static Map<String, Object> queryMethod(String taskId) {
59         try {
60             System.out.println(" ==>任務啟動" + taskId);
61             long startI = System.currentTimeMillis();
62             Thread.sleep(500);
63 //            System.out.println("   sleep:500ms");
64             System.out.println(" ==>任務終止" + taskId + " 任務時間:" + (System.currentTimeMillis() - startI));
65         } catch (InterruptedException e) {
66             e.printStackTrace();
67         }
68         Map<String, Object> resultMap = new HashMap<>();
69         Map<String, Object> head = new HashMap<>();
70         head.put("retFlag", "0000");
71         head.put("retMsg", "成功");
72         Map<String, Object> body = new HashMap<>();
73         body.put("aa", "11");
74         resultMap.put("head", head);
75         resultMap.put("body", body);
76         return resultMap;
77     }
78 }
示例3
 1  ==>任務啟動0
 2  ==>任務啟動1
 3  ==>任務啟動2
 4  ==>任務啟動3
 5  ==>任務啟動4
 6  ==>任務啟動5
 7  ==>任務啟動6
 8  ==>任務啟動7
 9  ==>任務啟動8
10  ==>任務啟動9
11  ==>任務終止0 任務時間:501
12 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
13  ==>任務終止4 任務時間:502
14  ==>任務終止3 任務時間:502
15  ==>任務終止2 任務時間:502
16  ==>任務終止1 任務時間:502
17 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
18 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
19 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
20 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
21  ==>任務終止6 任務時間:502
22  ==>任務終止5 任務時間:502
23 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
24 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
25  ==>任務終止8 任務時間:501
26  ==>任務終止7 任務時間:501
27 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
28 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
29  ==>任務終止9 任務時間:501
30 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
31 ====>took:525
32 resultMap = {aa1=11, aa0=11, aa3=11, aa2=11, aa5=11, aa4=11, aa7=11, aa6=11, aa9=11, aa8=11}
33 ==>took:526
示例3結果

 

 

關系圖:

下面是關系圖,望有助理解

 

 

 轉自:https://blog.csdn.net/sinat_39634657/article/details/81456810

https://blog.csdn.net/u012894692/article/details/80215140

https://blog.csdn.net/rexueqingchun/article/details/79025882

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM