1. 程式人生 > >Java並發編程之線程創建和啟動(Thread、Runnable、Callable和Future)

Java並發編程之線程創建和啟動(Thread、Runnable、Callable和Future)

出發 row 實現 pub 發的 interrupt 指定 系列 java並發

這一系列的文章暫不涉及Java多線程開發中的底層原理以及JMM、JVM部分的解析(將另文總結),主要關註實際編碼中Java並發編程的核心知識點和應知應會部分。

說在前面,Java並發編程的實質,是線程對象調用start方法啟動多線程,而線程對象則必須是Thread類或其子類實現。Runnable和Callable的作用類似於Comparable、Serializable,是用於被並發的類實現的接口,從而使得Thread類可以在初始化時傳入這個被並發的類。此是大前提。本文從多線程實現和啟動出發,對這些類或接口予以說明。

Thread

通過Thread的子類創建多線程的步驟如下:

1. 創建Thread的子類,並重寫run()方法,該方法即為線程執行體。

2. 創建Thread子類的對象,即為線程對象。

3. 調用線程對象的start()方法啟動線程。

 1 public class TestThread extends Thread{
 2     
 3     public TestThread(String name) {
 4         setName(name);
 5     }    
 6     @Override
 7     public void run() {
 8         while(!interrupted())
 9             System.out.println(getName() + "線程執行了");
10 } 11 public static void main(String[] args) { 12 13 TestThread t1 = new TestThread("first"); 14 TestThread t2 = new TestThread("second"); 15 //setDaemon()設置線程為守護線程 16 // t1.setDaemon(true); 17 // t2.setDaemon(true); 18 t1.start();
19 t2.start(); 20 t1.interrupt(); 21 } 22 }

Runnable

需要並發執行的類,可以通過實現Runnable接口,作為Thread的Target來創建線程對象。

 1 public class TestRunnable implements Runnable{
 2 
 3     @Override
 4     public void run() {
 5         while(true) {
 6             System.out.println("thread running...");
 7             try {
 8                 Thread.sleep(1000);
 9             } catch (InterruptedException e) {
10                 e.printStackTrace();
11             }
12         }
13     }
14     
15     public static void main(String[] args) {
16         //傳入TestRunnable對象作為Target, 開啟線程
17         Thread t = new Thread(new TestRunnable());
18         t.start();
19         //采用匿名內部類的方式創建和啟動線程
20         new Thread() {
21             @Override
22             public void run() {
23                 System.out.println("Thread的匿名內部類");
24             }
25         }.start();
26         //父類采用匿名實現Runnable接口, 並由子類繼承
27         new Thread(new Runnable() {
28             
29             @Override
30             public void run() {
31                 System.out.println("父類的線程");
32             }
33         }) {
34             @Override
35             public void run() {
36                 System.out.println("子類的線程");
37             }
38         }.start();        
39     }
40 }

Callable和Future

Java5開始提供了Callable接口,用於現有多線程開發的強力補充。Callable接口提供一個call()方法來構造線程執行體。

1. call()方法可以有返回值

2. call()方法可以聲明拋出異常

因此Callable接口沒有繼承Runnable接口,不能直接作為Thread類的Target來構造線程對象,所以Java5提供了Future接口來代表call方法的返回值。

Future提供了FutureTask實現類,該實現類實現了Future接口和Runnable接口,像橋梁一樣把線程執行體和線程對象連接了起來。

Future接口提供了若幹公共方法來操作Callable任務:

boolean cancel(boolean mayInterruptIfRunning): 試圖取消Future裏關聯的Callable任務

V get():返回Callable任務裏call方法的返回值。調用該方法會導致阻塞,必須等子線程完成後才得到返回值

V get(long timeout, TimeUnit unit):最多阻塞timeout和unit指定的時間,超時將拋出TimeoutException異常

boolean isCancelled():Callable任務正常完成前被取消,則返回true

boolean isDone():Callable任務已完成,則返回true

創建並啟動有返回值的線程步驟如下:

1. 創建Callable接口的實現類,並實現call方法作為線程執行體,再創建類的實例。Java8中可通過Lambda表達式進行。

2. 使用FutureTask類來包裝Callable實現類的對象

3. 使用FutureTask作為Thread對象的target

4. 使用FutureTask對象的get方法獲取子線程執行後的返回值

 1 public class TestCallable implements Callable<Integer>{
 2     //實現Callable並重寫call方法作為線程執行體, 並設置返回值1
 3     @Override
 4     public Integer call() throws Exception {
 5         System.out.println("Thread is running...");
 6         Thread.sleep(3000);
 7         return 1;
 8     }
 9     
10     public static void main(String[] args) throws InterruptedException, ExecutionException {
11         //創建Callable實現類的對象
12         TestCallable tc = new TestCallable();
13         //創建FutureTask類的對象
14         FutureTask<Integer> task = new FutureTask<>(tc);
15         //把FutureTask實現類對象作為target,通過Thread類對象啟動線程
16         new Thread(task).start();    
17         System.out.println("do something else...");
18         //通過get方法獲取返回值
19         Integer integer = task.get();    
20         System.out.println("The thread running result is :" + integer);    
21     }
22 }

總結一下,雖然繼承Thread類的開發方式相對簡單,但因為Java單繼承的限制,一般建議通過實現Runnable或Callable接口來創建並啟動多線程。

Java並發編程之線程創建和啟動(Thread、Runnable、Callable和Future)