java實現多執行緒的常用方式有兩種:繼承Thread類、實現Runnable介面實現run方法。

  • 繼承Thread實現方式:
public class ThreadTest extends Thread{

    private int ticket = 100;

    public void run() {
        while(ticket > 0){
            ticket--;
            System.out.println(Thread.currentThread().getName()+"tickets:"+ticket);
        }
    }

    public static void main(String[] args){
        ThreadTest threadTest = new ThreadTest();
        threadTest.start();
        System.out.println("主執行緒執行結束!");
    }
}
  • 實現Runnable實現方式:
public class RunableTest implements Runnable{

    private int ticket = 100;

    @Override
    public void run() {
        while(ticket > 0){
            ticket--;
            System.out.println(Thread.currentThread().getName()+"tickets:"+ticket);
        }
    }

    public static void main(String[] args){
        RunableTest runableTest = new RunableTest();
        Thread testThread = new Thread(runableTest);
        testThread.start();
        System.out.println("主執行緒結束!");
    }
}

可以看出這兩種方式實現多執行緒的方式非常相似,那它們之間有什麼區別呢?
設想個場景,火車站有100張票,有4個視窗進行售票,如何實現4個視窗共享100張票呢?

  • 案例一:
public class ThreadTest extends Thread{

    private int tickets = 100;

    public void run() {
        while(tickets > 0){
            tickets--;
            System.out.println(Thread.currentThread().getName()+"tickets:"+tickets);
        }
    }

    public static void main(String[] args){
        ThreadTest threadTest1 = new ThreadTest();
        ThreadTest threadTest2 = new ThreadTest();
        ThreadTest threadTest3 = new ThreadTest();
        ThreadTest threadTest4 = new ThreadTest();      
        threadTest1.start();
        threadTest2.start();
        threadTest3.start();
        threadTest4.start();
        System.out.println("主執行緒執行結束!");
    }
}

不難看出“案例一”沒有共享tickets資源,而是每個執行緒獨自建立了一個tickets資源,就相當於每個視窗都有100張票進行銷售。

  • 案例二:
public class ThreadTest extends Thread{


    private static int tickets = 100;


    public void run() {
        while(tickets > 0){
            tickets--;
            System.out.println(Thread.currentThread().getName()+"tickets:"+tickets);
        }
    }

    public static void main(String[] args){
        ThreadTest threadTest1 = new ThreadTest();
        ThreadTest threadTest2 = new ThreadTest();
        ThreadTest threadTest3 = new ThreadTest();
        ThreadTest threadTest4 = new ThreadTest();      
        threadTest1.start();
        threadTest2.start();
        threadTest3.start();
        threadTest4.start();
        System.out.println("主執行緒執行結束!");
    }
}

“案例二”把成員變數用static修飾後,tickets屬於ThreadTest類,不再屬於ThreadTest建立的物件,這樣就實現了多個執行緒對統一資源的共享。

  • 案例三:
public class ThreadTest extends Thread{

    private int tickets = 100;


    public void run() {
        while(tickets > 0){
            tickets--;
            System.out.println(Thread.currentThread().getName()+"tickets:"+tickets);
        }
    }

    public static void main(String[] args){
        ThreadTest threadTest1 = new ThreadTest();      
        threadTest1.start();
        threadTest1.start();
        threadTest1.start();
        threadTest1.start();
        System.out.println("主執行緒執行結束!");
    }
}

“案例三”建立了一個ThreadTest物件啟動了4次,系統它會啟動4個執行緒來處理tickets,通過結果分析並沒有建立4個執行緒處理,僅僅建立了一個執行緒。可見一個執行緒物件只能啟動一個執行緒,無論呼叫幾次start方法,都只是一個執行緒在執行。

  • 案例四:
public class RunableTest implements Runnable{

    private int tickets = 100;

    @Override
    public void run() {
        while(tickets > 0){
            tickets--;
            System.out.println(Thread.currentThread().getName()+"tickets:"+tickets);
        }       
    }

    public static void main(String args[]){
        RunableTest runableTest = new RunableTest();
        Thread thread1 = new Thread(runableTest);
        Thread thread2 = new Thread(runableTest);
        Thread thread3 = new Thread(runableTest);
        Thread thread4 = new Thread(runableTest);

        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        System.out.println("主執行緒執行結束!");
    }

}

“案例四”建立了四個執行緒,每個執行緒都呼叫runableTest物件的run方法,也就是說每個執行緒同時共享了runableTest物件中的tickets成員變數。

那麼繼承Thread和實現Runnable介面實現多執行緒有什麼區別呢?

  1. 由以上幾個案例可見,即使實現Runnable介面實現多執行緒,也是要通過建立Thread來啟動實現的,所以使用繼承Thread方式實現多執行緒在程式碼上可以簡化。

  2. Java不像C++支援多繼承,所以說在一個類已經有個父類的時候就無法繼承Thread來實現多執行緒,所以實現Runnable介面在擴充套件性上要比繼承Thread方式實現好。

  3. 分析案例不難看出,在多個執行緒同時執行一塊程式碼區域的時候使用實現Runnable介面的方式更加合適。把虛擬CPU(執行緒)同程式的程式碼,資料有效的分離,較好地體現了面向物件的設計思想。

備註:以上案例並不能實現多執行緒執行緒安全的共享tickets資源,案例的目標是為了描述兩種實現多執行緒的方式是如何實現共享資源的(非執行緒安全)。如果想了解如何保證資源執行緒安全的被多個執行緒處理,請持續關注筆者的《Java多執行緒》系列相關部落格,謝謝!