Java多線程_建立多線程的兩種經常使用方式淺析

Java實現多線程有兩種經常使用方法:繼承Thread類和實現Runable接口。下面學習下兩種方法的源碼。
1.繼承Thread類
這種方法實現多線程示例以下:java

class MyThread extends Thread{
    @Override
    public void run(){
        System.out.println("Hello thread");
    }
}
public class ThreadPool {
    public static void main(String args[]){
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

能夠看出,這種方法先是繼承Thread類,重寫Thread類的run方法,要使用多線程時再調用start方法。以前一直有一個疑問,爲何重寫的是run方法,而調用的是start方法呢。run方法和start方法有什麼關係呢?今天好好的研究下它們的關係。
點開start方法的源碼,能夠看到它的實現(爲了看起來簡潔,去掉註釋了):算法

public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }

從上面代碼能夠看出,start方法調用了start0方法,而點開start0能夠看到下面這行代碼設計模式

private native void start0();

start0方法被native修飾,是本地方法。查閱資料後發現JDK官方文檔在start方法有這樣的註釋:
Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread. 從這句話能夠知道start方法調用start0方法,而start0則會經過JVM調用run方法。過程能夠用下圖表示:
圖片描述
能夠看出這裏使用了設計模式中的模板方法模式。模板方法模式定義:是在父類中定義算法的骨架,把具體實延遲到子類中去,能夠在不改變一個算法的結構時可重定義該算法的某些步驟。真正實現邏輯的是run方法,所以使用者只須要重寫run方法。多線程

2.實現Runnable接口
經過實現Runnable接口實現多線程代碼示例以下:ide

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("Hello Runnable!");
    }
}
public class Demo {
    public static void main(String[] args) {
        new Thread(new MyRunnable()).start();
    }
}

先重寫了Runnable接口的run方法,而後將Runnable實例用做構造Thread的參數。打開run方法的源碼能夠看到它的實現以下:學習

/**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

由上面的註釋能夠知道若是構造Thread時傳遞了Runnable,則會執行runnable的run方法。不然須要重寫Thread類的run方法。this

經過上面的分析可知,不管仍是實現Runnable接口仍是繼承Thread類,其實底層都是重寫Thread的run方法,只不過第一種是直接重寫Thread類的run方法的實現,第二種是在另外一個類中重寫run方法,再傳遞到Thread中的run方法執行,也至關於重寫了run方法(經過調用其餘類中的run方法)。spa

像第二種方式其實用到了策略模式,把具體實現策略分離出來,再在執行的類中調用策略。線程

圖片描述設計

相關文章
相關標籤/搜索