使用線程
有三種使用線程的方法:
- 實現 Runnable 接口;
- 實現 Callable 接口;
- 繼承 Thread 類。
實現 Runnable
和 Callable
接口的類只能當做一個可以在線程中運行的任務,不是真正意義上的線程,因此最後還需要通過 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:
-
Runnable 與 Thread 不是對等的概念
在Thinking in Java
中,作者吐槽過Runnable
的命名,稱其叫做 Task 更爲合理。
在 Java 中,Runnable 只是一段用於描述任務的代碼段而已,是靜態的概念,需要通過線程來執行。而 Thread 更像是一個活體,自身就具有很多行爲,能夠用來執行任務。 -
僅僅當你確實想要重寫(override)一些已有行爲時,才使用繼承,否則請使用接口。