多線程擴展一、創建線程的三種方法詳細對比


1、繼承Thread類:

    步驟:①、定義類繼承Thread;

     ②、復寫Thread類中的run方法;
    目的:將自定義代碼存儲在run方法,讓線程運行
     ③、調用線程的start方法:
    該方法有兩步:啟動線程,調用run方法。
 1 public class ThreadDemo1 {  2  3 public static void main(String[] args) {  4  5 //創建兩個線程  6 ThreadDemo td = new ThreadDemo("zhangsan");  7 ThreadDemo tt = new ThreadDemo("lisi");  8 //執行多線程特有方法,如果使用td.run();也會執行,但會以單線程方式執行。  9  td.start(); 10  tt.start(); 11 //主線程 12 for (int i = 0; i < 5; i++) { 13 System.out.println("main" + ":run" + i); 14  } 15  } 16 } 17 //繼承Thread類 18 class ThreadDemo extends Thread{ 19 20 //設置線程名稱 21  ThreadDemo(String name){ 22 super(name); 23  } 24 //重寫run方法。 25 public void run(){ 26 for(int i = 0; i < 5; i++){ 27 System.out.println(this.getName() + ":run" + i);  //currentThread() 獲取當前線程對象(靜態)。 getName() 獲取線程名稱。 28  } 29  } 30 }

 2、實現Runnable接口: 接口應該由那些打算通過某一線程執行其實例的類來實現。類必須定義一個稱為run 的無參方法。

     實現步驟:  ①、定義類實現Runnable接口

          ②、覆蓋Runnable接口中的run方法

             將線程要運行的代碼放在該run方法中。

          ③、通過Thread類建立線程對象。

          ④、將Runnable接口的子類對象作為實際參數傳遞給Thread類的構造函數。

             自定義的run方法所屬的對象是Runnable接口的子類對象。所以要讓線程執行指定對象的run方法就要先明確run方法所屬對象

          ⑤、調用Thread類的start方法開啟線程並調用Runnable接口子類的run方法。

public class RunnableDemo { public static void main(String[] args) { RunTest rt = new RunTest(); //建立線程對象 Thread t1 = new Thread(rt); Thread t2 = new Thread(rt); //開啟線程並調用run方法。  t1.start(); t2.start(); } } //定義類實現Runnable接口 class RunTest implements Runnable{ private int tick = 10; //覆蓋Runnable接口中的run方法,並將線程要運行的代碼放在該run方法中。 public void run(){ while (true) { if(tick > 0){ System.out.println(Thread.currentThread().getName() + "..." + tick--); } } } }

 3、通過Callable和Future創建線程:

    實現步驟:①、創建Callable接口的實現類,並實現call()方法,改方法將作為線程執行體,且具有返回值。

         ②、創建Callable實現類的實例,使用FutrueTask類進行包裝Callable對象,FutureTask對象封裝了Callable對象的call()方法的返回值

         ③、使用FutureTask對象作為Thread對象啟動新線程。

         ④、調用FutureTask對象的get()方法獲取子線程執行結束后的返回值。

 1 public class CallableFutrueTest {  2 public static void main(String[] args) {  3 CallableTest ct = new CallableTest(); //創建對象  4 FutureTask<Integer> ft = new FutureTask<Integer>(ct); //使用FutureTask包裝CallableTest對象  5 for(int i = 0; i < 100; i++){  6 //輸出主線程  7 System.out.println(Thread.currentThread().getName() + "主線程的i為:" + i);  8 //當主線程執行第30次之后開啟子線程  9 if(i == 30){ 10 Thread td = new Thread(ft,"子線程"); 11  td.start(); 12  } 13  } 14 //獲取並輸出子線程call()方法的返回值 15 try { 16 System.out.println("子線程的返回值為" + ft.get()); 17 } catch (InterruptedException e) { 18  e.printStackTrace(); 19 } catch (ExecutionException e) { 20  e.printStackTrace(); 21  } 22  } 23 } 24 class CallableTest implements Callable<Integer>{ 25 //復寫call() 方法,call()方法具有返回值 26 public Integer call() throws Exception { 27 int i = 0; 28 for( ; i<100; i++){ 29 System.out.println(Thread.currentThread().getName() + "的變量值為:" + i); 30  } 31 return i; 32  } 33 }

 

三種方法對比:

    繼承Thread:線程代碼存放在Thread子類run方法中。

        優勢:編寫簡單,可直接用this.getname()獲取當前線程,不必使用Thread.currentThread()方法。

        劣勢:已經繼承了Thread類,無法再繼承其他類。

    實現Runnable:線程代碼存放在接口的子類的run方法中。

        優勢:避免了單繼承的局限性、多個線程可以共享一個target對象,非常適合多線程處理同一份資源的情形。

        劣勢:比較復雜、訪問線程必須使用Thread.currentThread()方法、無返回值。

    實現Callable:

        優勢:有返回值、避免了單繼承的局限性、多個線程可以共享一個target對象,非常適合多線程處理同一份資源的情形。

        劣勢:比較復雜、訪問線程必須使用Thread.currentThread()方法

  建議使用實現接口的方式創建多線程。

  返回多線程總結 請點擊:http://www.cnblogs.com/yjboke/p/8911220.html


免責聲明!

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



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