今天咱們來講一下線程的生命週期和經常使用 APIs:咱們須要很是清楚的知道線程的各類狀態,好比排查程序運行慢的緣由時,就須要看下是否是哪裏被阻塞了;另外它也是面試時很是喜歡問的,若是基礎內容都答很差,恐怕直接就掛了。java
本文分爲兩大部分,面試
1.線程的 6 大狀態;安全
2.多線程經常使用的 APIs:微信
join()多線程
wait()併發
notify()ide
yield()this
sleep()spa
currentThread()線程
getName()
getId()
getPriority()
setPriority()
stop()
線程狀態
關於線程的狀態,網上各類說法都有,比較流行的是 5 種或者 6 種。關於 5 種狀態的那個版本我沒有找到理論依據,若是有小夥伴清楚的也歡迎留言指出。
我這裏所寫的是根據 java.lang.Thread 的源碼,線程有如下 6 大狀態:
public enum State { NEW, RUNNABLE, BLOCKED, WAITTING, TIMED_WAITTING, TERMINATED; }
先上圖,咱們再依次來看。
1. New
A thread that has not yet started is in this state.
就是指線程剛建立,還沒啓動的時候,好比剛 new 了一個 thread。
MyThread myThread = new MyThread();
2. Runnable
A thread is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.
那麼接下來,天然就是要啓動線程了,也就是調用 thread 的 start() 方法。
myThread.start();
啓動以後,線程就進入了 Runnable 狀態。
此時全部的線程都會添加到一個等待隊列裏,等待「CPU 調度」。
若是搶佔到 CPU 的資源,那就執行;若是沒搶到,就等着唄,等當前正在執行的線程完成它能執行的時間片以後,再次搶佔。
要注意這裏在等待的通常是系統資源,而不是鎖或者其餘阻塞。
3. Blocked
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 calling wait() Object.
這裏給出了很是明確的 use case,就是被鎖在外面的才叫阻塞。因此這裏必需要有至少 2 個線程。
4. Waiting
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()。下一篇文章咱們會細講。
5. Timed_waiting
致使這個狀態的緣由以下:
Thread.sleep
Object.wait with timeout
Thread.join with timeout
LockSupport.parkNanos
LockSupport.parkUntil
其實就是在上一種狀態的基礎上,給了具體的時間限制。
那麼當時間結束後,線程就解放了。
6. Terminated
A thread that has exited is in this state.
這裏有 3 種狀況會終止線程:
執行完全部代碼,正常結束;
強制被結束,好比調用了 stop() 方法,如今已經被棄用;
拋出了未捕獲的異常。
線程一旦死亡就不能復生。
若是在一個死去的線程上調用 start() 方法,那麼程序會拋出 java.lang.IllegalThreadStateException。
接下來咱們說說多線程中經常使用的 11 個 APIs。
APIs
1. join()
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() 來實現的,咱們來看下這個方法。
2. wait() and notify()
wait() 其實並非 Thread 類的方法,而是 Object 裏面的方法。
該方法就是讓當前對象等待,直到另外一個對象調用 notify() 或者 notifyAll()。
固然了,咱們也能夠設定一個等待時長,到時間以後對象將會自動甦醒。
4. yield()
yield 自己的中文意思是屈服,用在這裏倒也合適。
yield() 表示當前線程主動讓出 CPU 資源一下,而後咱們再一塊兒去搶。
注意這裏讓一下真的只是一下,從「執行中」回到「等待 CPU 分配資源」,而後全部線程再一塊兒搶佔資源。
5. sleep()
顧名思義,這個方法就是讓當前線程睡一會,好比說,
myThread.sleep(1000); // 睡眠 1 秒鐘
它會拋出一個 InterruptedException 異常,因此還要 try catch 一下。
6. currentThread()
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 類型。
7. getName()
該方法能夠獲取當前線程名稱。
這個名稱能夠本身設置,好比:
Thread t = new Thread(new MyRunnable(), "壹齊學");
8. getId()
該方法是獲取線程的 Id.
9. getPriority()
線程也有優先級的哦~
雖然優先級高的線程並不能百分百保證必定會先執行,但它是有更大的機率被先執行的。
優先級的範圍是 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() 的異常。
10. setPriority()
固然啦,咱們也是能夠本身設置某個線程的優先級的。
設置的優先級也須要在規定的 1-10 的範圍內哦,若是不在這個範圍也會拋異常。
11. stop()
最後咱們來講下 stop() 方法,也是前文提到過的強制中止線程的一種方式,但如今已被棄用,由於會引發一些線程安全方面的問題。
好了,以上就是有關線程狀態和經常使用 API 的介紹了。相信你們看完以後對線程的整個流程應該有了清晰的認識,其實裏面還有不少細節我沒有展開,畢竟這是多線程的第 2 講,更深刻的內容咱們慢慢來。
本文轉載自微信公衆號「 碼農田小齊」,能夠經過如下二維碼關注。轉載本文請聯繫 碼農田小齊公衆號。
【編輯推薦】
【責任編輯:武曉燕 TEL:(010)68476606】