並發編程是Java語言的重要特性之一,“如何在Java中實現線程”是學習並發編程的入門知識,也是Java工程師面試必備的基礎知識。本文從線程說起,然后用代碼說明如何在Java中實現線程。
一、什么是線程?
線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。程序員可以通過它進行多處理器編程,也可以使用多線程對運算密集型任務提速。如果使用得當,線程可以有效地降低程序的開發和運維成本,同時能夠提升程序的性能。
二、線程和進程有什么區別?
線程是進程的子集,一個進程可以有很多線程。每個進程都有自己的內存空間,可執行代碼和唯一進程標識符(PID)。
每條線程並行執行不同的任務。不同的進程使用不同的內存空間(線程自己的堆棧),而所有的線程共享一片相同的內存空間(進程主內存)。別把它和棧內存搞混,每個線程都擁有單獨的棧內存用來存儲本地數據。
三、如何在Java中實現線程?
“如何在Java中實現線程”是學習並發編程入門的必備知識,對於這個問題也是眾說紛紜?打開百度搜索一下,一看便知。在信息爆炸的時代,我認為像孫悟空一樣有一雙火眼金睛是很必要的,分辨出哪些觀點更加准確,才能少走彎路。
那究竟有幾種方法可以實現線程?哪一家的言論更權威,被更多的開發者所認同呢?毋庸置疑,當然是官網文檔了。文檔地址
如圖中所示:
There are two ways to create a new thread of execution.
One is to declare a class to be a subclass of Thread. ...
The other way to create a thread is to declare a class that implements the Runnable interface. ...
現在可以肯定地說,在Java中實現線程有兩種方式, 分別是繼承 Thread 類和實現 Runnable 接口。下面分別用兩種方式實現線程。
- 方法一:繼承Thread類。
public class MyThread extends Thread {
public static void main(String[] args) {
new MyThread().start();
}
@Override
public void run() {
System.out.println("用Thread類實現線程");
}
}
- 方法二:實現Runnable接口。
public class MyRunnable implements Runnable {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
@Override
public void run() {
System.out.println("用Runnable接口實現線程");
}
}
- 深入分析
深入去看Thread類的源碼,可以看到Thread類實現了Runnable接口。
並且Thread類重寫了run方法, run 方法的代碼如下:
看過源碼可以發現,其實兩種方法實現線程的本質是一樣的,都是最終調用了 start()方法來新建線程。這兩個方法的最主要區別在於 run()方法的內容來源:
繼承Thread類: run()方法整體被重寫;
實現Runnable接口:最終調用 target.run()。
四、實現 Runnable 接口和繼承 Thread 類哪種方式更好?
Runnable和Thread兩者最大的區別是Thread是類而Runnable是接口,至於用類還是用接口,取決於繼承上的實際需要。Java類是單繼承的,實現多個接口可以實現類似多繼承的操作。
使用繼承 Thread 的方式的話,那么每次想新建一個任務,只能新建一個獨立的線程,而這樣做的損耗會比較大。而如果采用實現Runnable接口的話,Runnable就相當於一個作業,而Thread才是真正的處理線程,我們需要的只是定義這個作業,然后將作業交給線程去處理,這樣就達到了松耦合,也符合面向對象里面組合的使用。
五、總結
當下次再遇到這樣的面試題的時候,可以這樣硬剛面試官:
Java官方文檔說明有兩種方式實現線程:繼承Thread和實現Runnable接口。
但是深入源碼會發現,其實是一種本質方式,只能通過新建Thread類來創建線程,但是類里面的run方法有兩種方式來實現,第一種是重寫run方法,第二種實現Runnable接口的run方法,然后再把該runnable實例傳給Thread類。