Java Thread的基礎實踐方法

文章目的

讓讀者了解Java Thread的方法,目前Java Thread有三種實踐方法如下

  • 實作Runnable介面
  • 實作Callable介面
  • 繼承Thread類別

實作Runnable

Runnable是甚麼?

Runnable是一個介面提供一個run方法,原始程式碼如下

原始碼

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

原始碼要點

  • @FunctinalInerface annotation是標明此介面可以透過Java8 lambda的方式去實踐
  • run方法沒有回傳值,代表執行後無法接收解果

實踐方法

實作runnable中的run方法,在傳入thread的建構者創建新的thread,並且執行run

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Hi my name is Monster Lee");
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.run();
    }
}

實作Callable

甚麼是Callable?

Callable如同Runnable是一個需要實作的介面,而他與Runnable最大的差別在於,主程式呼叫後可以接取此執行緒的回傳值。接下來透過Java的原始碼來講解

原始碼

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

原始碼要點

  • 如同Runnable有@FunctionalInterface代表可以透過Lambda去實踐
  • 和Runnable不同的地方再與,他提供了V template並且在call時回傳這個template,代表在call結束時會回傳定義Callable template的物件
  • 所以Runnable和Callable的最大差異在於,執行後始否可以回傳值

實踐方法

實作Callable中的call方法,並且在宣告template時定義要回傳的物件,(範例為String),在要呼叫Callable的主程式中先定義FutureTask及回傳的template物件,並且將寫好的Callable傳入建構者中,Callable需要依靠FutureTask來接收回傳值,最後再新增一個Thread去跑此FutereTask,如果需要取回回傳值則直接呼叫FuterTask中的get方法及可以接收。

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "Hi my name is Monster Lee";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable mc = new MyCallable();
        FutureTask<String> ftData = new FutureTask<>(mc);
        Thread thread = new Thread(ftData);
        thread.run();
        System.out.println(ftData.get());
    }
}

繼承Thread

Thread是甚麼?

Thread是Java執行緒操作的基本,若要執行的話則直接呼叫start方法

原始碼

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

原始碼要點

  • Thread我們可以看到基本的start方法的實踐,主要透過呼叫start0這個方法,**而第33行的start0的前贅字native是Java用來呼叫C或C 語言的方法,簡單來說就是Java告訴OS我要呼叫一個start0我不知道是C或C++實踐你只要給我呼叫就好。*

實踐方法

繼承Thread Class並且改寫run方法,在主程序中執行start()方法

public class MyThread extends Thread {

    @Override
    public void run() {
        System.out.println("Hi my name is Monster Lee");
    }

    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
    }
}

總結

整篇文章主要介紹了

  • 實作Runnable介面
  • 實作Callable介面
  • 繼承Thread類別

而三種不同的實踐執行緒主要差別如下

  • 如果需要handle回傳值的話使用Callable
  • Runnable和Thread的差別主要在於
    • 實作介面和繼承Class
    • 這代表了實作介面的Runnable會比繼承Thread來的彈性(因為實作可以多從實作並且可以從中間改變行為,而繼承則只能硬生生地繼承Thread(連不必要的方法都須一覽接下)

留言

這個網誌中的熱門文章

Java Lambda Map篇

(InterviewBit) System Design - Design Cache System

設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)