今天簡單說一下Java三種多線程實現方式和區別,主要有實現Runnable、Callable和繼承Thread三種方式。java
實現Runnable的方式多線程
這種方式比較經常使用,當咱們的線程類有繼承其餘的類的狀況下(Java不支持類多繼承),而且線程任務不須要返回值的狀況下能夠選用這種方式。ide
1 public class ThreadRunnableDemo implements Runnable{ 2 3 /** 計數變量 */ 4 private int count = 0; 5 6 public static void main(String[] args) throws InterruptedException { 7 8 ThreadRunnableDemo threadRunnableDemo = new ThreadRunnableDemo(); 9 10 //實例化線程 11 Thread thread = new Thread(threadRunnableDemo, "threadRunnableDemoA"); 12 System.out.println(String.format("線程狀態preStart: %s", thread.getState())); 13 14 //啓動線程 15 thread.start(); 16 System.out.println(String.format("線程狀態afterStart: %s", thread.getState())); 17 18 //主線程休眠1000ms 19 Thread.sleep(1000); 20 System.out.println(String.format("線程狀態after1000ms: %s", thread.getState())); 21 22 } 23 24 @Override 25 public void run() { 26 27 count++; 28 29 System.out.println(String.format("線程名稱:%s, 線程狀態:%s, count:%s", 30 Thread.currentThread().getName(), Thread.currentThread().getState(), count)); 31 32 } 33 }
輸出結果:測試
1 線程狀態preStart: NEW 2 線程狀態afterStart: RUNNABLE 3 線程名稱:threadRunnableDemoA, 線程狀態:RUNNABLE, count:1 4 線程狀態after1000ms: TERMINATED
實現Callable的方式spa
當咱們執行線程須要返回值的時候那麼就必須選用實現Callable類的方式,由於目前只有這種方式能返回值。固然這種方式咱們也能夠不須要獲取返回值。線程
這種方式是經過FutureTask的get()方法(下面代碼的第22行)或者get(long timeout, TimeUnit unit)(下面代碼的第28行)方法獲取返回值。當咱們看Callable的接口定義的源碼會發現「public interface Callable<V> 」 ,咱們實現的時候是須要定義返回類型,以下面代碼所示。code
除此以外咱們還須要注意的是:當咱們經過FutureTask的get()方法去獲取線程的返回值的時候是要等到線程call()內容都執行完畢以後才能獲取獲得,而且get()方法後面的代碼必須等待,說明這必定是同步的,因此咱們能夠在真正須要線程返回值的時候才經過get()方法去獲取,以避免被阻塞。當咱們經過get(long timeout, TimeUnit unit)方式去獲取的時候能夠設置超時時間,若是超過所設置的超時時間都沒有獲取到線程返回的值則會拋出 java.util.concurrent.TimeoutException 異常,固然若是在get(long timeout, TimeUnit unit)以前用get()方式獲取了的話就不會拋異常。orm
實現Callable還有個好處就是能夠線程能夠拋異常,若是咱們須要在線程裏拋出異常的話也能夠選用這種方式,其餘兩種方式只能捕獲異常信息。blog
1 public class ThreadCallableDemo implements Callable<Integer>{ 2 3 /** 計數變量 */ 4 private int count = 0; 5 6 public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException { 7 8 ThreadCallableDemo threadCallableDemo = new ThreadCallableDemo(); 9 10 //經過FutureTask獲取返回值 11 FutureTask<Integer> taskA = new FutureTask<>(threadCallableDemo); 12 13 //實例化線程 14 Thread thread = new Thread(taskA, "threadCallableDemoA"); 15 System.out.println(String.format("線程狀態preStart: %s", thread.getState())); 16 17 //啓動線程 18 thread.start(); 19 System.out.println(String.format("線程狀態afterStart: %s", thread.getState())); 20 21 //經過FutureTask的get()方法獲取返回值 22 int result = taskA.get(); 23 System.out.println("是否同步測試...."); 24 System.out.println(String.format("result: %s", result)); 25 System.out.println(String.format("線程狀態afterGetResult1: %s", thread.getState())); 26 27 //經過FutureTask的get()方法獲取返回值 設置超時時間 單位爲ms 28 int resultWithTime = taskA.get(100, TimeUnit.MILLISECONDS); 29 System.out.println(String.format("resultWithTime: %s", resultWithTime)); 30 System.out.println(String.format("線程狀態afterGetResult2: %s", thread.getState())); 31 32 } 33 34 /** 35 * 實現Callable的call類 36 */ 37 @Override 38 public Integer call() throws Exception { 39 40 //自增 41 count++; 42 43 System.out.println(String.format("線程名稱:%s, 線程狀態:%s, count:%s", 44 Thread.currentThread().getName(), Thread.currentThread().getState(), count)); 45 System.out.println("休眠1000ms...."); 46 Thread.currentThread().sleep(1000); 47 return count; 48 } 49 }
輸出結果:繼承
1 線程狀態preStart: NEW 2 線程狀態afterStart: RUNNABLE 3 線程名稱:threadCallableDemoA, 線程狀態:RUNNABLE, count:1 4 休眠1000ms.... 5 是否同步測試.... 6 result: 1 7 線程狀態afterGetResult1: TERMINATED 8 resultWithTime: 1 9 線程狀態afterGetResult2: TERMINATED
繼承Thread的方式
Thread類實際上也是實現Runnable接口,因此當咱們繼承Thread的時候咱們即便不實現run()方法也不會報錯,這種方式也常常用。
下面我寫了兩種不一樣繼承Thread的代碼,你們能夠看一下區別,我在網上看到不少人說 繼承Thread實現多線程,線程間不能共享數據,可是我用下面的代碼1方式彷佛也能夠共享哇,歡迎你們提出質疑。
代碼1:
1 public class ThreadThreadDemo extends Thread{ 2 3 /** 計數變量 */ 4 private int count = 0; 5 6 public static void main(String[] args) throws InterruptedException { 7 8 ThreadThreadDemo threadThreadDemo = new ThreadThreadDemo(); 9 10 //實例化線程 11 Thread thread = new Thread(threadThreadDemo, "threadThreadDemoA"); 12 System.out.println(String.format("線程狀態preStart: %s", thread.getState())); 13 14 //啓動線程 15 thread.start(); 16 System.out.println(String.format("線程狀態afterStart: %s", thread.getState())); 17 18 //主線程休眠1000s 19 Thread.sleep(1000); 20 System.out.println(String.format("線程狀態after1000ms: %s", thread.getState())); 21 } 22 23 @Override 24 public void run() { 25 26 count++; 27 28 System.out.println(String.format("線程名稱:%s, 線程狀態:%s, count:%s", 29 Thread.currentThread().getName(), Thread.currentThread().getState(), count)); 30 } 31 }
輸出結果1:
1 線程狀態preStart: NEW 2 線程狀態afterStart: RUNNABLE 3 線程名稱:threadThreadDemoA, 線程狀態:RUNNABLE, count:1 4 線程狀態after1000ms: TERMINATED
代碼2:
1 public class ThreadThreadDemo extends Thread{ 2 3 /** 計數變量 */ 4 private int count = 0; 5 6 public static void main(String[] args) throws InterruptedException { 7 8 ThreadThreadDemo threadThreadDemo = new ThreadThreadDemo(); 9 10 //實例化線程 11 System.out.println(String.format("線程狀態preStart: %s", threadThreadDemo.getState())); 12 13 //啓動線程 14 threadThreadDemo.start(); 15 System.out.println(String.format("線程狀態afterStart: %s", threadThreadDemo.getState())); 16 17 //主線程休眠1000s 18 Thread.sleep(1000); 19 System.out.println(String.format("線程狀態after1000ms: %s", threadThreadDemo.getState())); 20 } 21 22 @Override 23 public void run() { 24 25 count++; 26 27 System.out.println(String.format("線程名稱:%s, 線程狀態:%s, count:%s", 28 Thread.currentThread().getName(), Thread.currentThread().getState(), count)); 29 } 30 }
輸出結果2:
1 線程狀態preStart: NEW 2 線程狀態afterStart: RUNNABLE 3 線程名稱:Thread-0, 線程狀態:RUNNABLE, count:1 4 線程狀態after1000ms: TERMINATED
最後總結:
若是有疑問或者有問題歡迎留言討論!