Java中線程的實現

在Java中要想實現多線程操作有兩種方法:
(1) 繼承Thread類
(2) 實現Runnable接口
一. 繼承Thread類
Thread類是在java.lang包中定義的,一個類只要繼承了Thread類,此類就稱爲多線程實現類。在Thread子類中,必須明確的覆寫Thread類中的run方法,此方法爲線程的主體。下面進行多線程的實現
【繼承Thread類實現多線程】

class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() { // 覆寫Thread類中的run()方法
        for (int i = 0; i < 10; i++) {
            System.out.println(name + "運行,i=" + i);
        }
    }
};

public class TreadDemo01 {
    public static void main(String[] args) {
        MyThread mt1 = new MyThread("線程A");
        MyThread mt2 = new MyThread("線程B");
        mt1.start();
        mt2.start();

    }
}

運行的結果:

線程A運行,i=0
線程B運行,i=0
線程B運行,i=1
線程B運行,i=2
線程B運行,i=3
線程B運行,i=4
線程B運行,i=5
線程B運行,i=6
線程A運行,i=1
線程B運行,i=7
線程A運行,i=2
線程B運行,i=8
線程A運行,i=3
線程A運行,i=4
線程B運行,i=9
線程A運行,i=5
線程A運行,i=6
線程A運行,i=7
線程A運行,i=8
線程A運行,i=9

編譯運行的結果可以看出兩個線程對象是交錯運行的,哪個線程對象搶到CPU資源,哪個線程就可以運行,所以程序每次運行的結果是不同的,在線程啓動時調用的start()方法,但是實際上調用的是run()方法定義的主題。
注意:一個線程對象不能重複調用start()方法,否則會異常。

如果一個類只能靠繼承Thread類才能實現多線程,則必定會受到單繼承侷限的影響,所以,一般要想實現多線程,還可以通過實現Runnable接口來完成。
二. 實現Runnable接口
在Java中也可以通過實現Runnable接口的方式來實現多線程,Runnable接口中定義了一個抽象方法:
public void run()
使用Runnable接口實現多線程:

class MyThread2 implements Runnable {
    private String name;

    public MyThread2(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(name + "運行,i=" + i);
        }
    }

}

以上代碼時通過Runnable接口來實現多線程的,但是從前面的代碼中可以知道,一個線程必須通過Thread類中的start()方法開啓。如果繼承了Thread類,則可以直接調用此方法,但是在實現Runnable接口時,此接口中並沒有start()方法,那麼該如何啓動多線程?實際上,此時還是依靠Thread類完成的。
【使用Thread類來啓動線程】

class MyThread2 implements Runnable {
    private String name;

    public MyThread2(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(name + "運行,i=" + i);
        }
    }

}

public class RunnableDemo01 {
    public static void main(String[] args) {
        MyThread2 mt1 = new MyThread2("線程A");
        MyThread2 mt2 = new MyThread2("線程B");
        Thread th1 = new Thread(mt1);
        Thread th2 = new Thread(mt2);
        th1.start();
        th2.start();
    }
}

運行結果爲:

線程A運行,i=0
線程B運行,i=0
線程B運行,i=1
線程B運行,i=2
線程B運行,i=3
線程B運行,i=4
線程B運行,i=5
線程B運行,i=6
線程B運行,i=7
線程B運行,i=8
線程B運行,i=9
線程A運行,i=1
線程A運行,i=2
線程A運行,i=3
線程A運行,i=4
線程A運行,i=5
線程A運行,i=6
線程A運行,i=7
線程A運行,i=8
線程A運行,i=9

以上兩種方法可以發現,無論使用哪種方式,最終都必須依靠Thread類才能啓動多線程。
三. Thread類和Runnable接口
通過Thread類和Runnable接口都可以實現多線程,那麼兩者有哪些聯繫和區別吶?下面觀察Thread類的定義
public class Thread extends Object implements Runnable
從Thread類的定義可以發現,Thread類也是Runnable接口的子類,但在Thread類中並沒有完全地實現Runnable接口中的run()方法。
Thread類的定義:

*/
public
class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
    public void run(){
    if(target!=null){
        target.run;
    }
}

從定義中可以發現,在Thread類中的run()方法調用的Runnable接口中的run()方法,也就是說此方法是由Runnable子類完成的,所以如果要通過Thread類實現多線程,則必須覆寫run()方法
實際上Thread類和Runnable接口也是有區別的,如果一個類繼承Thread類,則不適合於多個線程共享資源,而實現Runnable接口,就可以直接實現資源的共享
【繼承thread類而不能共享資源】

class MyThread extends Thread{  // 繼承Thread類,作爲線程的實現類
    private int ticket = 5 ;        // 表示一共有5張票
    public void run(){  // 覆寫run()方法,作爲線程 的操作主體
        for(int i=0;i<100;i++){
            if(this.ticket>0){
                System.out.println("賣票:ticket = " + ticket--) ;
            }
        }
    }
};
public class ThreadDemo04{
    public static void main(String args[]){
        MyThread mt1 = new MyThread() ;  // 實例化對象
        MyThread mt2 = new MyThread() ;  // 實例化對象
        mt1.start() ;   // 調用線程主體
        mt2.start() ;   // 調用線程主體

    }
};

運行結果:

賣票:ticket=5
賣票:ticket=5
賣票:ticket=4
賣票:ticket=3
賣票:ticket=2
賣票:ticket=1
賣票:ticket=4
賣票:ticket=3
賣票:ticket=2
賣票:ticket=1

以上程序通過Thread類實現多線程,程序中實現了2個線程,但是兩個線程分別買了各自的5張票,並沒有達到資源共享的目的。
【實現Runnable接口可以資源共享】

class MyThread2 implements Runnable {
    private int ticket = 5;

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (ticket > 0) {
                System.out.println("賣票:ticket=" + ticket--);
            }
        }
    }

}

public class RunnableDemo01 {
    public static void main(String[] args) {
        MyThread2 mt1 = new MyThread2();
        new Thread(mt1).start();
        new Thread(mt1).start();
        new Thread(mt1).start();

    }
}

運行結果:
賣票:t這裏寫代碼片icket=5
賣票:ticket=4
賣票:ticket=2
賣票:ticket=3
賣票:ticket=1
從程序的運行結果可以發現,雖然啓動了線程,但是3個線程一共才賣5張票,即ticket屬性被所有屬性被所有的行程對象共享。
可見,實現Runable接口相對於繼承Thread類說,有如下顯著的優勢:
(1) 適合多個相同程序代碼的線程去處理同一個資源的情況
(2) 可以避免由於Java單繼承特性帶來的侷限
(3) 增強了程序的健壯性,代碼能夠被多個線程共享,代碼與數據都是相互獨立的
所以,在開發中建議使用Runnable接口實現多線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章