摘要:前言本文描述線程線程狀態(tài)及狀態(tài)轉(zhuǎn)換,不會(huì)涉及過(guò)多理論,主要以代碼示例說(shuō)明線程狀態(tài)如何轉(zhuǎn)換。被終止線程執(zhí)行完畢正常結(jié)束或執(zhí)行過(guò)程中因未捕獲異常意外終止都會(huì)是線程進(jìn)入被終止?fàn)顟B(tài)。線程執(zhí)行完畢打印狀態(tài)。
前言
本文描述Java線程線程狀態(tài)及狀態(tài)轉(zhuǎn)換,不會(huì)涉及過(guò)多理論,主要以代碼示例說(shuō)明線程狀態(tài)如何轉(zhuǎn)換。
基礎(chǔ)知識(shí) 1. 線程狀態(tài)線程可以有6種狀態(tài):
New(新建)
Runnable(可運(yùn)行)
Blocked(被阻塞)
Waiting(等待)
Timed waiting(計(jì)時(shí)等待)
Terminated(被終止)
New:new Thread()后線程的狀態(tài)就是新建。
Runnable:線程一旦調(diào)用start()方法,無(wú)論是否運(yùn)行,狀態(tài)都為Runable,注意Runable狀態(tài)指示表示線程可以運(yùn)行,不表示線程當(dāng)下一定在運(yùn)行,線程是否運(yùn)行由虛擬機(jī)所在操作系統(tǒng)調(diào)度決定。
被阻塞:線程試圖獲取一個(gè)內(nèi)部對(duì)象的Monitor(進(jìn)入synchronized方法或synchronized塊)但是其他線程已經(jīng)搶先獲取,那此線程被阻塞,知道其他線程釋放Monitor并且線程調(diào)度器允許當(dāng)前線程獲取到Monitor,此線程就恢復(fù)到可運(yùn)行狀態(tài)。
等待:當(dāng)一個(gè)線程等待另一個(gè)線程通知調(diào)度器一個(gè)條件時(shí),線程進(jìn)入等待狀態(tài)。
計(jì)時(shí)等待:和等待類(lèi)似,某些造成等待的方法會(huì)允許傳入超時(shí)參數(shù),這類(lèi)方法會(huì)造成計(jì)時(shí)等待,收到其他線程的通知或者超時(shí)都會(huì)恢復(fù)到可運(yùn)行狀態(tài)。
被終止:線程執(zhí)行完畢正常結(jié)束或執(zhí)行過(guò)程中因未捕獲異常意外終止都會(huì)是線程進(jìn)入被終止?fàn)顟B(tài)。
2. 線程狀態(tài)轉(zhuǎn)換線程從“新建”到“被終止”會(huì)歷經(jīng)多次狀態(tài)轉(zhuǎn)換,所有可能的轉(zhuǎn)換如下圖:
【圖一】
觀察狀態(tài)轉(zhuǎn)化圖,我們發(fā)現(xiàn)“可運(yùn)行”狀態(tài)為所有狀態(tài)的必經(jīng)狀態(tài)。我們分析出四條基本的狀態(tài)轉(zhuǎn)換線路圖。
新建--->可運(yùn)行--->被終止
新建--->可運(yùn)行--->被阻塞--->可運(yùn)行--->被終止
新建--->可運(yùn)行--->等待--->可運(yùn)行--->被終止
新建--->可運(yùn)行--->計(jì)時(shí)等待--->可運(yùn)行--->被終止
“新建”和“被終止”狀態(tài)分別為起始和結(jié)束狀態(tài),和“可運(yùn)行”狀態(tài)不可逆。其他狀態(tài)均能和“可運(yùn)行”狀態(tài)相互轉(zhuǎn)換。
用代碼說(shuō)話(huà)讓我們用代碼演示線程狀態(tài)是如何轉(zhuǎn)換的,大家重點(diǎn)關(guān)注兩個(gè)問(wèn)題?
什么操作會(huì)改變線程狀態(tài)?
改變的狀態(tài)是如何恢復(fù)的?
一、 新建--->可運(yùn)行--->被終止這個(gè)狀態(tài)轉(zhuǎn)換時(shí)創(chuàng)建的線程生命周期。
/** * NEW->RUNNABLE->TERMINATED */ public class ThreadStateNRT { public static void main(String[] args) { Thread thread=new Thread(new Task()); print(thread.getName(),thread.getState()); thread.start(); //等待線程執(zhí)行完畢。 try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } print(thread.getName(),thread.getState()); } private static class Task implements Runnable{ @Override public void run() { print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } private static final String stringFormat="%s:%s"; private static void print(String threadName,Thread.State state){ System.out.println(String.format(stringFormat,threadName,state)); } }
其中,print()方法用來(lái)打印線程信息。后面的代碼示例均不在展示。
運(yùn)行程序結(jié)果為:
Thread-0:NEW二、 新建--->可運(yùn)行--->被阻塞--->可運(yùn)行--->被終止
Thread-0:RUNNABLE
Thread-0:TERMINATED
只有一種方法能出現(xiàn)阻塞狀態(tài),那就是synchronized同步原語(yǔ)。我們需要兩個(gè)線程其中一個(gè)線程被另一個(gè)阻塞來(lái)展示。
/** * NEW->RUNNABLE->BLOCKED->RUNNABLE->TERMINATED */ public class ThreadStateNRBRT { //鎖 private static final Object lock=new Object(); public static void main(String[] args) { //輔助線程,制造synchronized狀態(tài)。 Thread assistantThread = new Thread(new SynTask()); assistantThread.start(); try { //保證assistantThread先執(zhí)行。 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } Thread showThread = new Thread(new Task()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //因?yàn)闊o(wú)法判斷顯示線程何時(shí)執(zhí)行,所以循環(huán)直到顯示線程執(zhí)行。 while (true){ if(showThread.getState()==Thread.State.BLOCKED){ print(showThread.getName(), Thread.State.BLOCKED); break; } } //等待兩個(gè)線程執(zhí)行完畢。 try { assistantThread.join(); showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執(zhí)行完畢打印狀態(tài)。 print(showThread.getName(), showThread.getState()); } private static class SynTask implements Runnable { @Override public void run() { //鎖定一定時(shí)間 synchronized (lock){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } private static class Task implements Runnable { @Override public void run() { synchronized (lock){ print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } } }
執(zhí)行一下你有可能看到正確結(jié)果:
Thread-1:NEW
Thread-1:RUNNABLE
Thread-1:BLOCKED
Thread-1:RUNNABLE
Thread-1:TERMINATED
為什么是有可能呢?我們調(diào)整一下代碼,例如將加鎖的時(shí)間調(diào)小一點(diǎn):
private static class SynTask implements Runnable { @Override public void run() { //鎖定一定時(shí)間 synchronized (lock){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }
注意此處Thread.sleep(10),我們只鎖住十毫秒。
再運(yùn)行一下,控制臺(tái)可能打印出這樣的結(jié)果且程序不會(huì)結(jié)束:
Thread-1:NEW
Thread-1:RUNNABLE
Thread-1:RUNNABLE
造成以上結(jié)果的原因是我么無(wú)法保證兩個(gè)線程的執(zhí)行順序,也無(wú)法證主線程一定能打印出顯示線程阻塞的狀態(tài)。
while (true){ if(showThread.getState()==Thread.State.BLOCKED){ print(showThread.getName(), Thread.State.BLOCKED); break; } }
所以執(zhí)行在這段代碼死循環(huán)了。
調(diào)整一下代碼,保證不會(huì)因?yàn)閰?shù)調(diào)整改變線程之間的執(zhí)行順序和打印結(jié)果。
/** * NEW->RUNNABLE->BLOCKED->RUNNABLE->TERMINATED */ public class ThreadStateNRBRT_New { //鎖 private static final Object lock=new Object(); //鎖定標(biāo)志 private volatile static boolean lockFlag=true; //執(zhí)行順序 private volatile static int order=0; public static void main(String[] args) { //展示線程 Thread showThread = new Thread(new Task()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(), showThread.getState()); //輔助線程,制造synchronized狀態(tài)。 Thread assistantThread = new Thread(new SynTask()); assistantThread.start(); //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為BLOCKED,才讓輔助線程退出同步。 while (true){ if(showThread.getState()==Thread.State.BLOCKED){ print(showThread.getName(), Thread.State.BLOCKED); lockFlag=false; break; } } try { assistantThread.join(); showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執(zhí)行完畢打印狀態(tài)。 print(showThread.getName(), showThread.getState()); } private static class SynTask implements Runnable { @Override public void run() { while (true) { //保證先進(jìn)入同步范圍。 if (order == 0) { synchronized (lock) { //啟動(dòng)另一個(gè)同步 order=1; //等待主線程讀取到線程阻塞狀態(tài),退出同步。 while (lockFlag) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } break; } } } } private static class Task implements Runnable { @Override public void run() { while (true){ //保證后進(jìn)入同步范圍。 if (order==1){ synchronized (lock){ print(Thread.currentThread().getName(),Thread.currentThread().getState()); } break; } } } } }
我們用order保證線程進(jìn)入同步區(qū)的順序,用lockFlag保證只有在打印出顯示線程的被阻塞狀態(tài)后輔助線程才退出同步區(qū)。這樣無(wú)論如何執(zhí)行我們都會(huì)得到同樣的結(jié)果。
Thread-0:NEW三、 新建--->可運(yùn)行--->等待--->可運(yùn)行--->被終止
Thread-0:RUNNABLE
Thread-0:BLOCKED
Thread-0:RUNNABLE
Thread-0:TERMINATED
這里我們展示兩種三種方法造成線程的等待狀態(tài)
Object.wait()
java.util.concurrent.locks.Locke.lock()
java.util.concurrent.locks.Condition.await()
其他方法如Thread.join()等大家可以參考示例代碼自己實(shí)現(xiàn)。
1. Object.wait()/** * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRWRT { //鎖 private static final Object lock=new Object(); public static void main(String[] args) { //展示線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為WAITING,才讓輔助線程喚醒等待線程。 while (true){ if(showThread.getState()==Thread.State.WAITING){ print(showThread.getName(), Thread.State.WAITING); break; } } synchronized (lock){ lock.notify(); } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執(zhí)行完畢打印狀態(tài)。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 synchronized (lock){ try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }2. java.util.concurrent.locks.Locke.lock()
/** * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRWRTLock { //鎖 private static Lock lock=new ReentrantLock(); //鎖定標(biāo)志 private volatile static boolean lockFlag=true; //執(zhí)行順序 private volatile static int order=0; public static void main(String[] args) { //展示線程 Thread showThread = new Thread(new Task()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(), showThread.getState()); //輔助線程,制造synchronized狀態(tài)。 Thread assistantThread = new Thread(new SynTask()); assistantThread.start(); //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為BLOCKED,才讓輔助線程退出同步。 while (true){ if(showThread.getState()==Thread.State.WAITING){ print(showThread.getName(), Thread.State.WAITING); lockFlag=false; break; } } try { assistantThread.join(); showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執(zhí)行完畢打印狀態(tài)。 print(showThread.getName(), showThread.getState()); } private static class SynTask implements Runnable { @Override public void run() { while (true) { //保證先進(jìn)入同步范圍。 if (order == 0) { //加鎖 lock.lock(); try { order=1; while (lockFlag) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }finally { lock.unlock(); } break; } } } } private static class Task implements Runnable { @Override public void run() { while (true){ //保證后進(jìn)入同步范圍。 if (order==1){ lock.lock(); try{ print(Thread.currentThread().getName(),Thread.currentThread().getState()); }finally { lock.unlock(); } break; } } } } }3. java.util.concurrent.locks.Condition.await()
/** * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRWRTCondition { //鎖 private static Lock lock=new ReentrantLock(); private static Condition condition=lock.newCondition(); public static void main(String[] args) { //展示線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為WAITING,才讓輔助線程喚醒等待線程。 while (true){ if(showThread.getState()==Thread.State.WAITING){ print(showThread.getName(), Thread.State.WAITING); break; } } lock.lock(); try{ condition.signal(); }finally { lock.unlock(); } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執(zhí)行完畢打印狀態(tài)。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 lock.lock(); try{ try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } }finally { lock.unlock(); } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }4. 運(yùn)行結(jié)果
三段代碼的運(yùn)行結(jié)果都是:
Thread-0:NEW四、新建--->可運(yùn)行--->計(jì)時(shí)等待--->可運(yùn)行--->被終止
Thread-0:RUNNABLE
Thread-0:WAITING
Thread-0:RUNNABLE
Thread-0:TERMINATED
我們展示兩個(gè)方法造成計(jì)時(shí)等待狀態(tài)
Object.wait(long timeout)
java.util.concurrent.locks.Condition.await(long time, TimeUnit unit)
其他方法如Thread.sleep(long millis),Thread.join(long millis)等大家可以自己實(shí)現(xiàn)。
感覺(jué)凡是有超時(shí)方法的方法都能讓線程狀態(tài)進(jìn)入計(jì)時(shí)等待,但是這個(gè)沒(méi)有經(jīng)過(guò)驗(yàn)證,所以只是一個(gè)猜想。
/** * NEW->RUNNABLE->TIMED_WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRTWRT { //鎖 private static final Object lock=new Object(); public static void main(String[] args) { //展示線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為T(mén)IMED_WAITING。 while (true){ if(showThread.getState()==Thread.State.TIMED_WAITING){ print(showThread.getName(), Thread.State.TIMED_WAITING); break; } } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執(zhí)行完畢打印狀態(tài)。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 synchronized (lock){ try { lock.wait(1); } catch (InterruptedException e) { e.printStackTrace(); } } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }2. java.util.concurrent.locks.Condition.await(long time, TimeUnit unit)
/** * NEW->RUNNABLE->TIMED_WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRTWRTCondition { //鎖 private static Lock lock=new ReentrantLock(); private static Condition condition=lock.newCondition(); public static void main(String[] args) { //展示線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為T(mén)IMED_WAITING。 while (true){ if(Thread.State.TIMED_WAITING==showThread.getState()){ print(showThread.getName(), Thread.State.TIMED_WAITING); break; } } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執(zhí)行完畢打印狀態(tài)。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 lock.lock(); try{ try { condition.await(1,TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } }finally { lock.unlock(); } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }3. 運(yùn)行結(jié)果
兩段程序的運(yùn)行結(jié)果相同:
Thread-0:NEW結(jié)語(yǔ)
Thread-0:RUNNABLE
Thread-0:TIMED_WAITING
Thread-0:RUNNABLE
Thread-0:TERMINATED
至此,我們已經(jīng)介紹了線程狀態(tài)轉(zhuǎn)換的所有情況,了解線程狀態(tài)轉(zhuǎn)換對(duì)分析多線程代碼運(yùn)行很幫助。希望本篇文章對(duì)大家今后工作有所助力。
參考《Java核心技術(shù)+卷1》第九版
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/76926.html
摘要:一無(wú)鎖方案并發(fā)包中的原子類(lèi)都是基于無(wú)鎖方案實(shí)現(xiàn)的,相較于傳統(tǒng)的互斥鎖,無(wú)鎖并沒(méi)有加鎖解鎖線程切換的消耗,因此無(wú)鎖解決方案的性能更好,同時(shí)無(wú)鎖還能夠保證線程安全。線程首先讀取的值并加,如果此時(shí)有另一個(gè)線程更新了,則期望值和不相等,更新失敗。 一、無(wú)鎖方案 Java 并發(fā)包中的原子類(lèi)都是基于無(wú)鎖方案實(shí)現(xiàn)的,相較于傳統(tǒng)的互斥鎖,無(wú)鎖并沒(méi)有加鎖、解鎖、線程切換的消耗,因此無(wú)鎖解決方案的性能更好...
摘要:對(duì)象存不進(jìn)去,會(huì)又一次觸發(fā)垃圾回收。也就是說(shuō),它在進(jìn)行垃圾回收時(shí),必須暫停其他所有線程。我們來(lái)看一個(gè)名詞吞吐量。吞吐量運(yùn)行用戶(hù)代碼時(shí)間運(yùn)行用戶(hù)代碼時(shí)間垃圾收集時(shí)間。也就是說(shuō),收集器會(huì)嚴(yán)格控制吞吐量,至于這個(gè)吞吐量是多少,這個(gè)可以人為設(shè)置。 與其他語(yǔ)言相比,例如c/c++,我們都知道,java虛擬機(jī)對(duì)于程序中產(chǎn)生的垃圾,虛擬機(jī)是會(huì)自動(dòng)幫我們進(jìn)行清除管理的,而像c/c++這些語(yǔ)言平臺(tái)則需要...
摘要:本文將討論兩種可用于解決貝葉斯推理問(wèn)題的主要方法基于采樣的馬爾可夫鏈蒙特卡羅,簡(jiǎn)稱(chēng)方法和基于近似的變分推理,簡(jiǎn)稱(chēng)方法。而貝葉斯推理則是從貝葉斯的角度產(chǎn)生統(tǒng)計(jì)推斷的過(guò)程。貝葉斯推理問(wèn)題還可能會(huì)產(chǎn)生一些其他的計(jì)算困難。 全文共6415字,預(yù)計(jì)學(xué)習(xí)時(shí)長(zhǎng)20分鐘或更長(zhǎng) showImg(https://segmentfault.com/img/bVbvFZZ?w=1280&h=853); 圖片來(lái)...
閱讀 1091·2021-11-16 11:44
閱讀 1376·2019-08-30 13:12
閱讀 2414·2019-08-29 16:05
閱讀 3080·2019-08-28 18:29
閱讀 915·2019-08-26 13:41
閱讀 3236·2019-08-26 13:34
閱讀 2604·2019-08-26 10:35
閱讀 941·2019-08-26 10:28