1. 程式人生 > >詳解建立Java多執行緒的兩種方式

詳解建立Java多執行緒的兩種方式

      多執行緒的建立與使用是java工作學習中常見的內容,一直對多執行緒懷有神祕感,今天就把自己對多執行緒的理解分享給大家,供學習交流。

      程序:程序(Process)是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位,是作業系統結構的基礎。   

      執行緒:是程式中一個單一的順序控制流程,是cpu排程的最小單位。

      多執行緒:在單個程式中同時執行多個執行緒完成不同的工作,稱為多執行緒。

      執行緒的生命週期有五個階段:新建(new Thread)、就緒(runnable)、執行(running)、堵塞(blocked)、死亡(dead)。

      新建(new Thread):當建立Thread類的一個例項(物件)時,此執行緒進入新建狀態(未被啟動)。

      就緒(runnable):執行緒已經被啟動,正在等待被分配給CPU時間片,也就是說此時執行緒正在就緒佇列中排隊等候得到CPU資源。

      執行(running):執行緒獲得CPU資源正在執行任務(run()方法),此時除非此執行緒自動放棄CPU資源或者有優先順序更高的執行緒進入,執行緒將一直執行到結束。

      堵塞(blocked):由於某種原因導致正在執行的執行緒讓出CPU並暫停自己的執行,即進入堵塞狀態。

      死亡(dead):

當執行緒執行完畢或被其它執行緒殺死,執行緒就進入死亡狀態,這時執行緒不可能再進入就緒狀態等待執行。

      在java中建立多執行緒一般有兩種方式是,一種是繼承Thread類,並重寫run()方法;另一種是實現Runnable介面,並重寫run()方法。

      第一種:繼承Thread類

package com.xyfer;

public class ThreadDemo extends Thread(){

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            System.out.println("繼承Thread類第"+i+"次列印");
        }
    }
}

   測試類進行多執行緒測試,

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        ThreadDemo test1 = new ThreadDemo();
        ThreadDemo test2 = new ThreadDemo();
        test1.start();
        test1.start();
    }
}

控制檯列印:

繼承Thread類第0次列印

繼承Thread類第0次列印

繼承Thread類第1次列印

繼承Thread類第1次列印

繼承Thread類第2次列印

繼承Thread類第2次列印

繼承Thread類第3次列印

繼承Thread類第3次列印

繼承Thread類第4次列印

繼承Thread類第4次列印

再執行一次:

繼承Thread類第0次列印

繼承Thread類第0次列印

繼承Thread類第1次列印

繼承Thread類第1次列印

繼承Thread類第2次列印

繼承Thread類第3次列印

繼承Thread類第2次列印

繼承Thread類第4次列印

繼承Thread類第3次列印

繼承Thread類第4次列印

程式啟動執行main時,java虛擬機器啟動一個程序,主執行緒在main()方法被呼叫的時候建立,main()方法執行在主執行緒中,隨著main()方法中的兩個物件的start()方法呼叫,另外兩個執行緒也被啟動,這樣,整個程式就在多執行緒下運行了。

多次執行,從控制檯列印結果可以看出,多執行緒並不是按順序執行程式碼的,而是隨機執行的,作業系統隨機在多個執行緒之間切換。start()方法呼叫後並不是立即執行相應執行緒程式碼,而是把執行緒程式碼變成可執行狀態,等待作業系統隨機執行。

      第二中:實現Runnable介面

package com.xyfer;

public class ThreadRunnable implements Runnable(){

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            System.out.println("實現Runnable介面第"+i+"次列印");
        }
    }
}

測試類進行多執行緒測試:(通過Thread的構造方法傳入Runnable介面的實現類建立Thread類例項呼叫start()方法啟動執行緒)

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        new Thread(new ThreadRunnable()).start();
        new Thread(new ThreadRunnable()).start();
    }
}

控制檯輸出結果:

實現Runnable介面第0次列印

實現Runnable介面第0次列印

實現Runnable介面第1次列印

實現Runnable介面第1次列印

實現Runnable介面第2次列印

實現Runnable介面第2次列印

實現Runnable介面第3次列印

實現Runnable介面第3次列印、

此時多執行緒仍然是隨機執行執行緒,多執行幾次程式就會發現控制檯列印結果順序不一樣。

多執行緒中的join()方法

下面介紹一下多執行緒中的join()方法,很多情況下,主執行緒啟動了子執行緒,但是通常子執行緒要做大量的耗時工作,因此會出現主執行緒先於子執行緒執行結束。但是有時候主執行緒是需要子執行緒的執行結果的,這時候就需要使用多執行緒的join()方法來控制主執行緒等待子執行緒執行完畢後再結束主執行緒。

以繼承Thread類為例:

package com.xyfer;

public class ThreadDemo extends Thread(){

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            System.out.println("繼承Thread類第"+i+"次列印");
        }
    }
}

測試類:

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        System.out.println("主執行緒開啟。");
        ThreadDemo test1 = new ThreadDemo();
        ThreadDemo test2 = new ThreadDemo();
        test1.start();
        test1.start();
        System.out.println("主執行緒結束。");
    }
}

控制檯列印結果:

主執行緒開啟。

主執行緒結束。

繼承Thread類第0次列印

繼承Thread類第1次列印

繼承Thread類第2次列印

繼承Thread類第3次列印

繼承Thread類第4次列印

繼承Thread類第0次列印

繼承Thread類第1次列印

繼承Thread類第2次列印

繼承Thread類第3次列印

繼承Thread類第4次列印

從控制檯列印結果來看,主執行緒先於子執行緒執行結束。使用join()方法後就能保證主執行緒在子執行緒之後執行結束。

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        System.out.println("主執行緒開啟。");
        ThreadDemo test1 = new ThreadDemo();
        ThreadDemo test2 = new ThreadDemo();
        test1.start();
        test1.start();
        try {
            test1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            test2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主執行緒結束。");
    }
}

控制檯列印結果:

主執行緒開啟。

繼承Thread類第0次列印

繼承Thread類第1次列印

繼承Thread類第2次列印

繼承Thread類第3次列印

繼承Thread類第4次列印

繼承Thread類第0次列印

繼承Thread類第1次列印

繼承Thread類第2次列印

繼承Thread類第3次列印

繼承Thread類第4次列印

主執行緒結束。

從控制檯列印結果可以看出,join()方法能保證主執行緒在子執行緒執行結束之後再執行結束。