Java中,線程的狀態(tài)使用一個(gè)枚舉類型來描述的。這個(gè)枚舉一共有6個(gè)值: NEW(新建)、RUNNABLE(運(yùn)行)、BLOCKED(鎖池)、TIMED_WAITING(定時(shí)等待)、WAITING(等待)、TERMINATED(終止、結(jié)束)。
但是大多數(shù)人的理解和上面的這六種還是有些差別,通常會(huì)加上阻塞狀態(tài),可運(yùn)行狀態(tài),掛起狀態(tài)。
在API中 java.lang.Thread.State 這個(gè)枚舉中給出了六種線程狀態(tài),
這是Thread類描述線程狀態(tài)的枚舉類的源代碼:
為五通橋等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及五通橋網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站制作、網(wǎng)站建設(shè)、五通橋網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* 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
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
線程從創(chuàng)建、運(yùn)行到結(jié)束總是處于下面五個(gè)狀態(tài)之一:新建狀態(tài)、就緒狀態(tài)、運(yùn)行狀態(tài)、阻塞狀態(tài)及死亡狀態(tài)。
線程狀態(tài)轉(zhuǎn)換圖:
當(dāng)用new操作符創(chuàng)建一個(gè)線程時(shí), 例如new Thread(r),線程還沒有開始運(yùn)行,此時(shí)線程處在新建狀態(tài)。 當(dāng)一個(gè)線程處于新生狀態(tài)時(shí),程序還沒有開始運(yùn)行線程中的代碼。
一個(gè)新創(chuàng)建的線程并不自動(dòng)開始運(yùn)行,要執(zhí)行線程,必須調(diào)用線程的start()方法。當(dāng)線程對象調(diào)用start()方法即啟動(dòng)了線程,start()方法創(chuàng)建線程運(yùn)行的系統(tǒng)資源,并調(diào)度線程運(yùn)行run()方法。當(dāng)start()方法返回后,線程就處于就緒狀態(tài)。
處于就緒狀態(tài)的線程并不一定立即運(yùn)行run()方法,線程還必須同其他線程競爭CPU時(shí)間,只有獲得CPU時(shí)間才可以運(yùn)行線程。因?yàn)樵趩蜟PU的計(jì)算機(jī)系統(tǒng)中,不可能同時(shí)運(yùn)行多個(gè)線程,一個(gè)時(shí)刻僅有一個(gè)線程處于運(yùn)行狀態(tài)。因此此時(shí)可能有多個(gè)線程處于就緒狀態(tài)。對多個(gè)處于就緒狀態(tài)的線程是由
Java運(yùn)行時(shí)系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。
當(dāng)線程獲得CPU時(shí)間后,它才進(jìn)入運(yùn)行狀態(tài),真正開始執(zhí)行run()方法.
線程運(yùn)行過程中,可能由于各種原因進(jìn)入阻塞狀態(tài):
有兩個(gè)原因會(huì)導(dǎo)致線程死亡:
1.run方法正常退出而自然死亡,
據(jù)官方源碼,一個(gè)線程有六個(gè)狀態(tài),沒有阻塞狀態(tài),沒有可運(yùn)行,沒有掛起狀態(tài)。這里先列出各個(gè)線程狀態(tài)發(fā)生的條件,下面將會(huì)對每種狀態(tài)進(jìn)行詳細(xì)解析:
| 線程狀態(tài) | 導(dǎo)致狀態(tài)發(fā)生修改的條件 |
|---|---|
| NEW(新建) | 線程剛被創(chuàng)建,但是并未啟動(dòng)。還沒調(diào)用start()方法。 |
| Runnable(可運(yùn)行) | 線程可以在java虛擬機(jī)中運(yùn)行的狀態(tài),可能正在運(yùn)行自己代碼,也可能沒有,這取決于操作系統(tǒng)處理器。 |
| Blocked(鎖阻塞) | 當(dāng)一個(gè)線程試圖獲取一個(gè)對象鎖,而該對象鎖被其他的線程持有,則該線程進(jìn)入Blocked狀態(tài);當(dāng)該線程持有鎖時(shí),該線程將變成Runnable狀態(tài)。 |
| Waiting(無限 等待) | 一個(gè)線程在等待另一個(gè)線程執(zhí)行一個(gè)(喚醒)動(dòng)作時(shí),該線程進(jìn)入Waiting狀態(tài)。進(jìn)入這個(gè)狀態(tài)后是不能自動(dòng)喚醒的,必須等待另一個(gè)線程調(diào)用notify或者notifyAll方法才能夠喚醒。 |
| Timed Waiting(計(jì)時(shí)等待) | 同waiting狀態(tài),有幾個(gè)方法有超時(shí)參數(shù),調(diào)用他們將進(jìn)入TimedWaiting狀態(tài)。這一狀態(tài)將一直保持到超時(shí)期滿或者接收到喚醒通知。帶有超時(shí)參數(shù)的常用方法有Thread.sleep、Object.wait。 |
| Teminated(被 終止) | 因?yàn)閞un方法正常退出而死亡,或者因?yàn)闆]有捕獲的異常終止了run方法而死亡。 |
我們不需要去研究這幾種狀態(tài)的實(shí)現(xiàn)原理,我們只需知道在做線程操作中存在這樣的狀態(tài)。那我們怎么去理解這幾個(gè)狀態(tài)呢,新建與被終止還是很容易理解的,我們就研究一下線程從Runnable(可運(yùn)行)狀態(tài)與非運(yùn)行狀態(tài)之間 的轉(zhuǎn)換問題。
當(dāng)線程調(diào)用sleep()方法或當(dāng)前線程中有其他線程調(diào)用了帶時(shí)間參數(shù)的join()方法的時(shí)候進(jìn)入了定時(shí)等待狀態(tài)(TIMED_WAITING)。
代碼示例:
/**
* @author bruceliu
* @create 2019-06-01 22:35
* @description TimedWaiting(計(jì)時(shí)等待)
*/
public class Test1 {
public static void main(String[] args) {
Thread1 t1 = new Thread1();
Thread2 t2 = new Thread2();
t1.setThread2(t2);
t1.start();
t2.start();
}
}
//Thread1負(fù)責(zé)打印兩個(gè)線程的狀態(tài)。
class Thread1 extends Thread {
private Thread2 t2;
public void setThread2(Thread2 t2) {
this.t2 = t2;
}
@Override
public void run() {
System.out.println("進(jìn)入t1線程");
for (int i = 0; i < 5; i++) {
try {
System.out.println("t1 的狀態(tài): " + getState());
System.out.println("t2 的狀態(tài): " + t2.getState());
System.out.println();
//為了減少打印次數(shù),所以t1每打印一次睡1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
class Thread2 extends Thread {
@Override
public void run() {
System.out.println("進(jìn)入t2線程,馬上進(jìn)入睡眠");
try {
//睡眠5秒鐘。
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2睡眠結(jié)束");
}
}通過案例可以發(fā)現(xiàn),sleep方法的使用還是很簡單的。我們需要記住下面幾點(diǎn):
sleep()中指定的時(shí)間是線程不會(huì)運(yùn)行的最短時(shí)間。因此,sleep()方法不能保證該線程睡眠到期后就開始立刻執(zhí)行。
Timed Waiting 線程狀態(tài)圖:
Blocked狀態(tài)在API中的介紹為:一個(gè)正在阻塞等待一個(gè)監(jiān)視器鎖(鎖對象)的線程處于這一狀態(tài)。
如果我們已經(jīng)學(xué)完同步機(jī)制,那么這個(gè)狀態(tài)是非常好理解的了。比如,線程A與線程B代碼中使用同一鎖,如果線程A獲取到鎖,線程A進(jìn)入到Runnable狀態(tài),那么線程B就進(jìn)入到Blocked鎖阻塞狀態(tài)。
這是由Runnable狀態(tài)進(jìn)入Blocked狀態(tài)。除此Waiting以及Time Waiting狀態(tài)也會(huì)在某種情況下進(jìn)入阻塞狀態(tài),而這部分內(nèi)容作為擴(kuò)充知識點(diǎn)帶領(lǐng)大家了解一下。
Blocked 線程狀態(tài)圖:
Wating狀態(tài)在API中介紹為:一個(gè)正在無限期等待另一個(gè)線程執(zhí)行一個(gè)特別的(喚醒)動(dòng)作的線程處于這一狀態(tài)。那么我們之前遇到過這種狀態(tài)嗎?答案是并沒有,但并不妨礙我們進(jìn)行一個(gè)簡單深入的了解。我們通過一段代碼來學(xué)習(xí)一下:
package com.bruceliu.demo7;
/**
* @author bruceliu
* @create 2019-05-30 16:59
* @description
*/
public class WaitingTest {
public static Object obj = new Object();
public static void main(String[] args) {
// 演示waiting
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (obj) {
try {
System.out.println(Thread.currentThread().getName() + "=== 從waiting狀態(tài)醒來,獲取到鎖對象,繼續(xù)執(zhí)行了");
obj.wait(); //無限等待
//obj.wait(5000); //計(jì)時(shí)等待, 5秒 時(shí)間到,自動(dòng)醒來
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "=== 從waiting狀 態(tài)醒來,獲取到鎖對象,繼續(xù)執(zhí)行了");
}
}
}
}, "等待線程").start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) { //每隔3秒 喚醒一次
try {
System.out.println(Thread.currentThread().getName() + "‐‐‐‐‐ 等待3秒鐘");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + "‐‐‐‐‐ 獲取到鎖對 象,調(diào)用notify方法,釋放鎖對象");
obj.notify();
}
}
}
}, "喚醒線程").start();
}
}
通過上述案例我們會(huì)發(fā)現(xiàn),一個(gè)調(diào)用了某個(gè)對象的 Object.wait 方法的線程會(huì)等待另一個(gè)線程調(diào)用此對象的Object.notify()方法 或 Object.notifyAll()方法。其實(shí)waiting狀態(tài)并不是一個(gè)線程的操作,它體現(xiàn)的是多個(gè)線程間的通信,可以理解為多個(gè)線程之間的協(xié)作關(guān)系,多個(gè)線程會(huì)爭取鎖,同時(shí)相互之間又存在協(xié)作關(guān)系。就好比在公司里你和你的同事們,你們可能存在晉升時(shí)的競爭,但更多時(shí)候你們更多是一起合作以完成某些任務(wù)。當(dāng)多個(gè)線程協(xié)作時(shí),比如A,B線程,如果A線程在Runnable(可運(yùn)行)狀態(tài)中調(diào)用了wait()方法那么A線程就進(jìn)入了Waiting(無限等待)狀態(tài),同時(shí)失去了同步鎖。假如這個(gè)時(shí)候B線程獲取到了同步鎖,在運(yùn)行狀態(tài)中調(diào)用了notify()方法,那么就會(huì)將無限等待的A線程喚醒。注意是喚醒,如果獲取到鎖對象,那么A線程喚醒后就進(jìn)入Runnable(可運(yùn)行)狀態(tài);如果沒有獲取鎖對象,那么就進(jìn)入到Blocked(鎖阻塞狀態(tài))。
Waiting 線程狀態(tài)圖:
到此為止我們已經(jīng)對線程狀態(tài)有了基本的認(rèn)識,想要有更多的了解,詳情可以見下圖:

我們在翻閱API的時(shí)候會(huì)發(fā)現(xiàn)Timed Waiting(計(jì)時(shí)等待) 與 Waiting(無限等待) 狀態(tài)聯(lián)系還是很緊密的,比如Waiting(無限等待) 狀態(tài)中wait方法是空參的,而timed waiting(計(jì)時(shí)等待) 中wait方法是帶參的。這種帶參的方法,其實(shí)是一種倒計(jì)時(shí)操作,相當(dāng)于我們生活中的小鬧鐘,我們設(shè)定好時(shí)間,到時(shí)通知,可是如果提前得到(喚醒)通知,那么設(shè)定好時(shí)間在通知也就顯得多此一舉了,那么這種設(shè)計(jì)方案其實(shí)是一舉兩得。如果沒有得到(喚醒)通知,那么線程就處于Timed Waiting狀態(tài),直到倒計(jì)時(shí)完畢自動(dòng)醒來;如果在倒計(jì)時(shí)期間得到(喚醒)通知,那么線程從Timed Waiting狀態(tài)立刻喚醒。
分享文章:并發(fā)編程專題(三)-線程的狀態(tài)
本文路徑:http://chinadenli.net/article12/jpssgc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁設(shè)計(jì)公司、面包屑導(dǎo)航、品牌網(wǎng)站設(shè)計(jì)、小程序開發(fā)、網(wǎng)站設(shè)計(jì)、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)