java多執行緒之執行緒的基本使用

墨廿枉發表於2020-11-08

執行緒的基本介紹

程式&執行緒

程式:程式是程式碼在資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位。 執行緒: 執行緒是程式的一個執行路徑,一個程式中至少有一個執行緒,也可以有多執行緒,多執行緒會共享程式的資源。

執行緒資源分配

作業系統分配資源的時候會把資源分配給程式,但cpu比較特殊,它是被分配到執行緒的,因為真正使用資源的是執行緒(如果程式中只有一個執行緒,可以理解為單執行緒),所以也可以說cpu的資源分配資源是執行緒。cpu使用時間片的方式讓執行緒輪流佔用,當前執行緒使用完成後會讓出時間片,交給其他執行緒使用,等再次輪到自己的時候才繼續執行。那麼如何記錄程式執行到哪裡了呢。java中採用計數器的方式來記錄讓出cpu的執行地址,當可以再次執行的時候,java可以根據計數器指定地址繼續執行。 java中啟動main函式就相當於啟動了一個jvm(java虛擬機器)程式。 每個執行緒都有自己的棧資源,用來儲存該執行緒的區域性變數,這些區域性變數是該執行緒私有的,除此之外棧還有來呼叫執行緒儲存的棧貞。 堆是程式中的最大一塊記憶體,它的資源是共享的。主要用來存放使用new操作建立的物件例項。 `方法區用來存放jvm載入的類,常量及靜態變數等資訊,也是共享的。

執行緒建立和執行

java中有三種建立執行緒的方式,1繼承Thread、2實現Runnable、3使用FutureTask

繼承Thread
Thread類在java.lang包中是一個執行緒類,該類中的方法都是關於執行緒的,感興趣的可以看一下。我們先來了解如何建立執行緒:

public class MyThread  extends Thread{
    @Override
    public void run() {
        System.out.println("這個是我建立的一個執行緒");
    }


    public static void main(){
        MyThread  my=new MyThread();
        my.start();
    }
}

如上面MyThread繼承自Thread類,並且重寫了run方法,表示建立了一個執行緒。在main函式中建立一個MyThread的例項,然後呼叫start方法啟動執行緒。這裡需要提示一下,線上程中,如果呼叫run方法執行只是表示呼叫了一個方法,並不能表示呼叫了一個執行緒,而呼叫start方法之後,表示該執行緒已經啟動了。
注意:在呼叫start方法之後並不一位置執行緒可以執行了,而是執行緒處於就緒狀態,在等待cpu分配時間片,一旦執行緒獲得時間片就可以馬上執行,執行緒run執行完成之後就會處於中止狀態。(這裡可以看下執行緒的五種狀態)
繼承Thread的我們可以直接通過this呼叫該執行緒中的方法(如果已經看了Thread類的方法,就會知道執行緒有很多方法),但是之前學過物件導向我們會知道java只允許單繼承,所以一旦繼承了Thread類,那麼就不能再去繼承其他類了,所以執行緒又提供了一個介面供開發者實現。

實現Runnable介面

public class RunableTask implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable實現");
    }


    public  static  void main(String []args){
        RunableTask runableTask=new RunableTask();
        new Thread(runableTask).start();
        new Thread(runableTask).start();
        new Thread(runableTask).start();


    }
}    

如上面的程式碼,實現了Runnable介面,可以繼續繼承其他累了。但是要注意,在Runable介面中沒有start方法,所以不能直接啟動執行緒,而是需要Thread來接收Runnable介面程式碼來實現執行緒的啟動,如果在Runable中呼叫執行緒中的方法,需要使用Thread.currentThread()方法。
上面兩種方式實現了執行緒,有一個小的缺點,就是沒有返回值,如果需要返回值的話,可以使用FutrueTask。

實現FutrueTask介面
public class CallerTask  implements Callable<String> {


    @Override
    public String call() throws Exception {
        return "hello thread";
    }


    public static  void main(String []args){
        //建立非同步任務
        FutureTask<String > futureTask=new FutureTask<String>(new CallerTask());
        //啟動執行緒
        new Thread(futureTask).start();
        try {
            //等待任務執行返回結果
            String s = futureTask.get();
            System.out.println(s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

上面程式碼實現了Cllable介面,重寫了call方法(介面的泛型就是call方法的返回值)。FutureTask通過構造方法接收Callable的子類,建立了非同步執行緒。最後通過FutureTask的get方法執行了方法,獲得返回值。

總結:

繼承Thread的有優點是方便傳參,可以在子類裡面新增成員變數,通過set方法或構造方式進行傳遞,可以直接的獲取執行緒中的方法.。但是java只支援單繼承,不能繼承其他類。 實現Runnable的介面,只能使用主執行緒裡被宣告為final的變數,不限制繼承。 實現FutureTask介面,可以使用返回值。

相關文章