上一篇文章咱們聊了多線程的基礎內容,好比爲何要使用多線程,線程和進程之間的不一樣,以及建立線程的 4 種方式。本文已收錄至個人 Github: https://github.com/xiaoqi6666/NYCSDEjava
今天咱們來講一下線程的生命週期和經常使用 APIs:咱們須要很是清楚的知道線程的各類狀態,好比排查程序運行慢的緣由時,就須要看下是否是哪裏被阻塞了;另外它也是面試時很是喜歡問的,若是基礎內容都答很差,恐怕直接就掛了。git
本文分爲兩大部分,github
關於線程的狀態,網上各類說法都有,比較流行的是 5 種或者 6 種。關於 5 種狀態的那個版本我沒有找到理論依據,若是有小夥伴清楚的也歡迎留言指出。web
我這裏所寫的是根據 java.lang.Thread
的源碼,線程有如下 6 大狀態:面試
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITTING,
TIMED_WAITTING,
TERMINATED;
}
先上圖,咱們再依次來看。安全
A thread that has not yet started is in this state.多線程
就是指線程剛建立,還沒啓動的時候,好比剛 new
了一個 thread
。編輯器
MyThread myThread = new MyThread();
A thread is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.ide
那麼接下來,天然就是要啓動線程了,也就是調用 thread
的 start()
方法。學習
myThread.start();
啓動以後,線程就進入了 Runnable
狀態。
此時全部的線程都會添加到一個等待隊列裏,等待「CPU 調度」。
若是搶佔到 CPU 的資源,那就執行;若是沒搶到,就等着唄,等當前正在執行的線程完成它能執行的時間片以後,再次搶佔。
要注意這裏在等待的通常是系統資源,而不是鎖或者其餘阻塞。
Thread state for a thread blocked waiting for a monitor lock.
A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after callingwait()
Object.
這裏給出了很是明確的 use case
,就是被鎖在外面的才叫阻塞。因此這裏必需要有至少 2 個線程。
A thread in the waiting state is waiting for another thread to perform a particular action.
那具體有哪些緣由呢?
A thread is in the waiting state due to calling one of the following methods:
Object.wait with no timeout Thread.join with no timeout LockSupport.park
因此說,當調用了
wait()
,
join()
,
park()
這裏的等待狀態是沒有時間限制的,能夠無限的等下去... 因此須要有人來喚醒:
wait()
進入等待狀態的,須要有
notify()
或者
notifyAll()
方法來喚醒;
join()
進入等待狀態的,須要等待目標線程運行結束。
好比在生產者消費者模型裏,當沒有商品的時候,消費者就須要等待,等待生產者生產好了商品發 notify()
。下一篇文章咱們會細講。
致使這個狀態的緣由以下:
Thread.sleep Object.wait with timeout Thread.join with timeout LockSupport.parkNanos LockSupport.parkUntil
其實就是在上一種狀態的基礎上,給了具體的時間限制。
那麼當時間結束後,線程就解放了。
A thread that has exited is in this state.
這裏有 3 種狀況會終止線程:
stop()
方法,如今已經被棄用;
線程一旦死亡就不能復生。
若是在一個死去的線程上調用 start()
方法,那麼程序會拋出 java.lang.IllegalThreadStateException
。
接下來咱們說說多線程中經常使用的 11 個 APIs。
join()
方法會強制讓該線程執行,而且一直會讓它執行完。
好比上一篇文章的例子是兩個線程交替執行的,那麼咱們這裏該下,改爲調用小齊線程.join()
,那麼效果就是先輸出 小齊666
。
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println("小齊666:" + i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new MyRunnable());
t.start();
t.join();
for(int i = 0; i < 100; i++) {
System.out.println("主線程" + i + ":齊姐666");
}
}
}
因此 join()
可以保證某個線程優先執行,並且會一直讓它執行完,再回歸到公平競爭狀態。
join()
方法實際上是用 wait()
來實現的,咱們來看下這個方法。
wait()
其實並非 Thread
類的方法,而是 Object
裏面的方法。
該方法就是讓當前對象等待,直到另外一個對象調用 notify()
或者 notifyAll()
。
固然了,咱們也能夠設定一個等待時長,到時間以後對象將會自動甦醒。
yield
自己的中文意思是屈服,用在這裏倒也合適。
yield()
表示當前線程主動讓出 CPU 資源一下,而後咱們再一塊兒去搶。
注意這裏讓一下真的只是一下,從「執行中」回到「等待 CPU 分配資源」,而後全部線程再一塊兒搶佔資源。
顧名思義,這個方法就是讓當前線程睡一會,好比說,
myThread.sleep(1000); // 睡眠 1 秒鐘
它會拋出一個 InterruptedException
異常,因此還要 try catch
一下。
Returns a reference to the currently executing thread object.
該方法是獲取當前線程對象。
注意它是一個 static
方法,因此直接經過 Thread
類調用。
好比打印當前線程
System.out.println(Thread.currentThread());
前文的例子中,它會輸出:
Thread[Thread-0,5,main]
Thread[main,5,main]
沒錯,它的返回值也是 Thread
類型。
該方法能夠獲取當前線程名稱。
這個名稱能夠本身設置,好比:
Thread t = new Thread(new MyRunnable(), "壹齊學");
該方法是獲取線程的 Id
.
線程也有優先級的哦~
雖然優先級高的線程並不能百分百保證必定會先執行,但它是有更大的機率被先執行的。
優先級的範圍是 1-10
,咱們來看源碼:
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
若是不在這個範圍,JDK 拋出 IllegalArgumentException()
的異常。
固然啦,咱們也是能夠本身設置某個線程的優先級的。
設置的優先級也須要在規定的 1-10
的範圍內哦,若是不在這個範圍也會拋異常。
最後咱們來講下 stop()
方法,也是前文提到過的強制中止線程的一種方式,但如今已被棄用,由於會引發一些線程安全方面的問題。
好了,以上就是有關線程狀態和經常使用 API 的介紹了。相信你們看完以後對線程的整個流程應該有了清晰的認識,其實裏面還有不少細節我沒有展開,畢竟這是多線程的第 2 講,更深刻的內容咱們慢慢來。
若是你喜歡這篇文章,記得給我點贊留言哦~大家的支持和承認,就是我創做的最大動力,咱們下篇文章見!
我是小齊,紐約程序媛,終生學習者,天天晚上 9 點,雲自習室裏不見不散!
**更多幹貨文章見個人 Github: https://github.com/xiaoqi6666/NYCSDE