java多執行緒之建立執行緒的三種方式優缺點
Java使用Thread類代表執行緒,所有的執行緒物件都必須是Thread類或其子類的例項。
一、繼承Thread類建立執行緒類
1.重寫run方法。該run()方法的方法體就代表了執行緒需要完成的任務。
2.建立Thread子類的例項。
3.呼叫執行緒物件的start()方法來啟動該執行緒。
public class TestCode1 extends Thread { private int i; public void run() { for(;i<100;i++) { System.out.println(getName()+" "+i); } } public static void main(String[] args) { for(int i=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); if(i==20){ new TestCode1().start(); new TestCode1().start(); } } } }
二、實現Runnable介面建立執行緒類
1.定義Runnable的實現類,重寫run()方法。
2.建立Runnable實現類的例項,並以此作為Thread的target來建立物件,該物件才是真正的執行緒物件。
public class TestCode2 implements Runnable { private int i; public void run() { for(;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); } } public static void main(String[] args) { for(int i=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); if(i==20){ TestCode2 test=new TestCode2(); new Thread(test,"新執行緒1").start(); new Thread(test,"新執行緒2").start(); } } } }
三、使用Callable和Future建立執行緒
1.建立Callable介面的實現類,並實現Call()方法,該方法將作為執行緒執行體,且該方法有返回值,再建立Callable實現類的例項。從Java8開始,可以直接使用Lambda表示式建立Callable物件。
2.使用FutureTask來包裝Callable物件,該FutureTask物件封裝了該Callable物件的call方法的返回值。
3.使用FutureTask物件作為Thread物件的target建立並啟動新執行緒。
4.呼叫FutureTask物件的get()方法來獲取子執行緒執行結束後的返回值。
public class TestCode3 { public static void main(String[] args) { TestCode3 test = new TestCode3(); FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{ int i=0; for(;i<100;i++){ System.out.println(Thread.currentThread().getName()+"迴圈變數i的值:"+i); } return i; }); for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"迴圈變數i的值:"+i); if(i==20){ new Thread(task,"有返回值的執行緒").start(); } try{ System.out.println("子執行緒的返回值:"+task.get()); } catch (Exception e) { e.printStackTrace(); } } } }
四、淺談三種方式優劣勢
通過繼承Thread類或實現Runnable、Callable介面都可以實現多執行緒,不過實現Runnable介面與實現Callable介面的方式基本相同,只是Callable接口裡定義的方法有返回值,可以宣告丟擲異常而已。因此可以將實現Runnable介面和實現Callable介面歸為一種方式。這種方式與繼承Thread方式之間的主要差別如下。
1.採用實現Runnable、Callable介面的方式建立多執行緒的優缺點:
優勢:(1)執行緒類只是實現了Runnable介面與Callable介面,還可以繼承其他類。
(2)在這種方式下,多個執行緒可以共享一個target物件,所以非常適合多個相同執行緒來處理同一份資源的情況,從而可以將CPU、程式碼和資料分開,形成清晰的模型,較好地體現了面向物件的思想。
劣勢:程式設計稍稍複雜,如果需要訪問當前執行緒,則必須使用Thread.currentThread()方法。
2.採用繼承Thread類的方法建立多執行緒的優缺點:
劣勢:因為執行緒類已經繼承了Thread類,所以不能再繼承其他父類。
優勢:編寫簡單,如果需要訪問當前執行緒,則無須使用Thread.currentThread()方法,直接使用this即可獲得當前執行緒。
五、總結
鑑於上面分析,因此一般推薦採用實現Runnable介面、Callable介面的方式來建立多執行緒。