首頁 > Java > Java入門 > 3種Java創建執行緒的方式和區別

3種Java創建執行緒的方式和區別

青灯夜游
發布: 2019-11-27 16:12:38
轉載
3002 人瀏覽過

在java中如何建立執行緒?以下這篇文章為大家介紹3種創建線程的方式以及差異。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

3種Java創建執行緒的方式和區別

在java中如果要建立執行緒的話,一般有3種方法:

1、繼承Thread類別;

2、實作Runnable介面;

3、使用Callable和Future建立執行緒。

【推薦學習:java影片教學

#1. 繼承Thread類別

##繼承Thread類別的話,必須重寫run方法,在run方法中定義需要執行的任務。

class MyThread extends Thread{
    private static int num = 0;
     
    public MyThread(){
        num++;
    }
     
    @Override
    public void run() {
        System.out.println("主动创建的第"+num+"个线程");
    }
}
登入後複製
建立好了自己的執行緒類別之後,就可以建立執行緒物件了,然後透過start()方法去啟動執行緒。請注意,不是呼叫run()方法啟動線程,run方法中只是定義需要執行的任務,如果呼叫run方法,即相當於在主執行緒中執行run方法,跟普通的方法呼叫沒有任何區別,此時並不會建立一個新的執行緒來執行定義的任務。

public class Test {
    public static void main(String[] args)  {
        MyThread thread = new MyThread();
        thread.start();
    }
}
 
 
class MyThread extends Thread{
    private static int num = 0;
     
    public MyThread(){
        num++;
    }
     
    @Override
    public void run() {
        System.out.println("主动创建的第"+num+"个线程");
    }
}
登入後複製
在上面程式碼中,透過呼叫start()方法,就會建立一個新的執行緒了。為了分辨start()方法呼叫和run()方法呼叫的區別,請看下面一個範例:

public class Test {
    public static void main(String[] args)  {
        System.out.println("主线程ID:"+Thread.currentThread().getId());
        MyThread thread1 = new MyThread("thread1");
        thread1.start();
        MyThread thread2 = new MyThread("thread2");
        thread2.run();
    }
}
 
 
class MyThread extends Thread{
    private String name;
     
    public MyThread(String name){
        this.name = name;
    }
     
    @Override
    public void run() {
        System.out.println("name:"+name+" 子线程ID:"+Thread.currentThread().getId());
    }
}
登入後複製
運行結果:

從輸出結果可以得出以下結論:

1)thread1和thread2的執行緒ID不同,thread2和主執行緒ID相同,說明透過run方法呼叫並不會建立新的線程,而是在主執行緒中直接執行run方法,跟普通的方法調用沒有任何區別;

2)雖然thread1的start方法調用在thread2的run方法前面調用,但是先輸出的是thread2的run方法調用的相關信息,說明新執行緒建立的過程不會阻塞主執行緒的後續執行。

2. 實作Runnable介面

#在Java中建立執行緒除了繼承Thread類別之外,還可以透過實作Runnable介面來實作類似的功能。實作Runnable介面必須重寫其run方法。

下面是一個例子:

public class Test {
    public static void main(String[] args)  {
        System.out.println("主线程ID:"+Thread.currentThread().getId());
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
 
 
class MyRunnable implements Runnable{
     
    public MyRunnable() {
         
    }
     
    @Override
    public void run() {
        System.out.println("子线程ID:"+Thread.currentThread().getId());
    }
}
登入後複製
Runnable的中文意思是“任務”,顧名思義,透過實作Runnable接口,我們定義了一個子任務,然後將子任務交由Thread去執行。注意,這種方式必須將Runnable作為Thread類別的參數,然後透過Thread的start方法來建立一個新執行緒來執行該子任務。如果呼叫Runnable的run方法的話,是不會建立新執行緒的,這根普通的方法呼叫沒有任何差別。

事實上,檢視Thread類別的實作原始碼會發現Thread類別是實作了Runnable介面的。

在Java中,這2種方式都可以用來建立執行緒去執行子任務,具體選擇哪一種方式要看自己的需求。直接繼承Thread類別的話,可能比實作Runnable介面看起來更簡潔,但是由於Java只允許單繼承,所以如果自訂類別需要繼承其他類,則只能選擇實作Runnable介面。

3. 使用Callable和Future建立執行緒

和Runnable介面不一樣,Callable介面提供了一個call()方法作為執行緒執行體,call()方法比run()方法功能強大。

建立並啟動有傳回值的執行緒的步驟如下:

    建立Callable介面的實作類,並實作call()方法,然後建立該實作類別的實例(從java8開始可以直接使用Lambda表達式建立Callable物件)。
  1. 使用FutureTask類別來包裝Callable對象,該FutureTask物件封裝了Callable物件的call()方法的傳回值
  2. 使用FutureTask物件作為Thread物件的target建立並啟動執行緒(因為FutureTask實作了Runnable介面)
  3. 呼叫FutureTask物件的get()方法來取得子執行緒執行結束後的回傳值
以下是一個範例:

public class Main {

  public static void main(String[] args){

   MyThread3 th=new MyThread3();

   //使用Lambda表达式创建Callable对象

     //使用FutureTask类来包装Callable对象

   FutureTask<Integer> future=new FutureTask<Integer>(

    (Callable<Integer>)()->{

      return 5;

    }

    );

   new Thread(task,"有返回值的线程").start();//实质上还是以Callable对象来创建并启动线程

    try{

    System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回

    }catch(Exception e){

    ex.printStackTrace();

   }

  }

}
登入後複製

三種建立執行緒方式比較:

實作Runnable和實作Callable介面的方式基本上相同,不過是後者執行call()方法有回傳值,後者執行緒執行體run()方法無回傳值,因此可以把這兩種方式歸為一種這種方式與繼承Thread類別的方法之間的差別如下:

1、執行緒只是實作Runnable或實作Callable接口,還可以繼承其他類別。

2、這種方式下,多個執行緒可以共享一個target對象,非常適合多執行緒處理同一份資源的情況。

3、但是程式設計稍微複雜,如果需要存取當前線程,必須呼叫Thread.currentThread()方法。

4、繼承Thread類別的執行緒類別不能再繼承其他父類別(Java單繼承決定)。

PS:一般建議採用實作介面的方式來建立多執行緒

本文來自 java入門 欄目,歡迎學習!

以上是3種Java創建執行緒的方式和區別的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:cnblogs.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板