在Java中,建立線程有以下幾種方式:
通過實現 Runnable 介面;
通過繼承 Thread 類本身;
通過 Callable 和 Future 建立線程。
通過實現 Runnable 介面來建立線程
建立線程最簡單的方式就是直接實現Runnable介面,該介面定義了一個run()方法,在我們的實作類別中通過對該方法的實現來定義我們自己的任務,這樣使得我們在建立並啟動線程之後能夠執行我們自己的任務。比如我們要執行一個倒計時的任務,我們就可以像下面的代碼一樣實現:
public class RunnableDemo implements Runnable { @Override public void run() { System.out.println("倒計時開始:"); for(int i = 0; i < 10 ; i++){ System.out.println(10-i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Thread thread = new Thread(new RunnableDemo(),"Runnable-Thread"); thread.start(); }}
通過繼承Thread來建立線程
建立一個線程的第二種方法是建立一個新的類,該類繼承 Thread 類(關於Thread類我們會在後續的文章中詳細闡述),然後建立一個該類的執行個體。
繼承類必須重寫 run() 方法,該方法是新線程的進入點。它也必須調用 start() 方法才能執行。
該方法儘管被列為一種多線程實現方式,但是本質上也是實現了 Runnable 介面的一個執行個體。
通過繼承Thread重寫上面的倒計時任務如下:
public class ThreadDemo extends Thread { public void run() { System.out.println("倒計時開始:"); for(int i = 0; i < 10 ; i++){ System.out.println(10-i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { ThreadDemo thread = new ThreadDemo(); thread.start(); }}
通過 Callable 和 Future 建立線程
Runnable是執行工作的獨立任務,但是他不返回任何值,如果你希望任務在完成時能夠返回一個值,那麼可以實現Callable介面來實現。Callable介面是一種具有型別參數的泛型介面,通過查看它的源碼我們可以發現,它的型別參數所表示的是從call()中返回的值的類型。Callable類型的任務可以有兩種執行方式:
藉助FutureTask執行
藉助Executor來運執行
藉助FutureTask執行
建立 Callable 介面的實作類別,並實現 call() 方法,該 call() 方法將作為線程執行體,並且有傳回值。
建立 Callable 實作類別的執行個體,使用 FutureTask 類來封裝 Callable 對象,該 FutureTask 對象封裝了該 Callable 對象的 call() 方法的傳回值。
使用 FutureTask 對象作為 Thread 對象的 target 建立並啟動新線程。
調用 FutureTask 對象的 get() 方法來獲得子線程執行結束後的傳回值。
public class CallableThreadDemo implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("線程在進行計算"); Thread.sleep(1000); int sum = 0; for(int i=0;i<100;i++) sum += i; return sum; } public static void main(String[] args) throws InterruptedException, ExecutionException { Callable<Integer> mycallabletask = new CallableThreadDemo(); FutureTask<Integer> futuretask= new FutureTask<Integer>(mycallabletask); new Thread(futuretask).start(); System.out.println("傳回值:"+futuretask.get()); }}
藉助Executor來運執行
藉助Executor必須使用ExecutorService.submit()方法調用它,下面是對上一個執行個體的改造:
public class CallableThreadDemo2 implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("線程在進行計算"); Thread.sleep(1000); int sum = 0; for(int i=0;i<100;i++) sum += i; return sum; } public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService exec = Executors.newCachedThreadPool(); Future<Integer> future = exec.submit(new CallableThreadDemo2()); System.out.println("傳回值:"+ future.get()); exec.shutdown(); }}
三種方式對比
採用實現 Runnable、Callable 介面的方式建立多線程時,線程類只是實現了 Runnable 介面或 Callable 介面,還可以繼承其他類。
使用繼承 Thread 類的方式建立多線程時,編寫簡單,如果需要訪問當前線程,則無需使用 Thread.currentThread() 方法,直接使用 this 即可獲得當前線程。
參考:
http://www.runoob.com/java/java-multithreading.html
《java編程思想》