線程:基礎知識

使用線程

有三種使用線程的方法:

  • 實現 Runnable 接口;
  • 實現 Callable 接口;
  • 繼承 Thread 類。

實現 RunnableCallable 接口的類只能當做一個可以在線程中運行的任務,不是真正意義上的線程,因此最後還需要通過 Thread 來調用。可以理解爲任務是通過線程驅動從而執行的。

實現 Runnable 接口

需要實現接口中的 run() 方法。

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        // ...
    }
}Copy to clipboardErrorCopied

通過 Runnable 實例創建一個 Thread 實例,然後調用 Thread 實例的 start() 方法來啓動線程。

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

實現 Callable 接口

與 Runnable 相比,Callable 可以有返回值,返回值通過 FutureTask 進行封裝。

public class MyCallable implements Callable<Integer> {
    public Integer call() {
        return 123;
    }
}

通過 Callable實例創建一個 FutureTask 實例,通過 FutureTask 實例創建 Thread 實例,然後調用 Thread 實例的 start() 方法來啓動線程。

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

繼承 Thread 類

同樣也是需要實現 run() 方法,因爲 Thread 類也實現了 Runable 接口。

當調用 start() 方法啓動一個線程時,虛擬機會將該線程放入就緒隊列中等待被調度,當一個線程被調度時會執行該線程的 run() 方法。

public class MyThread extends Thread {
    public void run() {
        // ...
    }
}
public static void main(String[] args) {
    MyThread mt = new MyThread();
    mt.start();
}

實現接口 VS 繼承 Thread

一般而言,推薦實現接口,主要是由於大多數情況下,人們並不會特別去關注線程的行爲,也不會去改寫Thread已有的行爲或方法,僅僅是期望執行任務而已。
因此,使用接口的方式能避免引入一些並不需要的東西,同時也不會影響繼承其他類,並使程序更加靈活。

Tips:

  1. Runnable 與 Thread 不是對等的概念
    Thinking in Java 中,作者吐槽過 Runnable 的命名,稱其叫做 Task 更爲合理。
    在 Java 中,Runnable 只是一段用於描述任務的代碼段而已,是靜態的概念,需要通過線程來執行。而 Thread 更像是一個活體,自身就具有很多行爲,能夠用來執行任務。

  2. 僅僅當你確實想要重寫(override)一些已有行爲時,才使用繼承,否則請使用接口。

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