??博客主頁:?【小扳_-CSDN博客】
?感謝大家點(diǎn)贊??收藏?評(píng)論?
文章目錄
? ? ? ? 1.0 線程等待
? ? ? ? 1.1?線程等待 -?join() 方法
? ? ? ? 1.1.1 main 線程中等待多個(gè)線程
? ? ? ? 1.1.2 main 線程等待 t2?線程且t2?線程等待 t1?線程
? ? ? ? 1.1.3 其他線程阻塞等待 main 線程
? ? ? ? 1.1.4 在指定的時(shí)間內(nèi)阻塞等待
? ? ? ? 1.2?線程等待 - Thread.sleep() 方法
? ? ? ? 2.0 線程狀態(tài)
? ? ? ? 2.1 新建狀態(tài) - NEW
? ? ? ? 2.2 就緒狀態(tài) - Runnable
? ? ? ? 2.3 終止?fàn)顟B(tài) -Terminated
? ? ? ? 2.4 等待狀態(tài) - Waiting
? ? ? ? 2.5 超時(shí)等待狀態(tài) - Time_Waiting
? ? ? ? 2.6 阻塞狀態(tài) - Blocked
? ? ? ? 2.7 線程狀態(tài)之間的相互轉(zhuǎn)換圖
? ? ? ? 1.0 線程等待
????????在線程編程中,線程等待是指一個(gè)線程暫停執(zhí)行,直到某個(gè)條件滿足或者其他線程執(zhí)行完畢后再繼續(xù)執(zhí)行。線程等待的方法:join() 方法、Thread.sleep() 方法等等
? ? ? ? 1.1?線程等待 -?join() 方法
?????? join() 方法是 Thread 類的一個(gè)方法,用于讓一個(gè)線程等待另一個(gè)線程執(zhí)行完畢。當(dāng)在一個(gè)線程對(duì)象上調(diào)用 join() 方法時(shí),當(dāng)前線程會(huì)被阻塞,直到被調(diào)用的線程執(zhí)行完畢。
????????具體來說,調(diào)用?thread.join()?會(huì)使當(dāng)前線程等待 thread 線程執(zhí)行完畢。如果 thread 線程已經(jīng)執(zhí)行完畢,那么 join() 方法會(huì)立即返回;如果 thread 線程還在執(zhí)行,當(dāng)前線程會(huì)被阻塞,直到 thread 線程執(zhí)行完畢。
代碼如下:
public class demo1 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ for (int i = 0; i < 1000; i++) { System.out.println("正在執(zhí)行 thread 線程"); } }); thread.start(); thread.join(); System.out.println("執(zhí)行 main 線程"); } }
? ? ? ? main 線程調(diào)用 thread.join() ,就會(huì)阻塞 main 線程繼續(xù)執(zhí)行,會(huì)讓 thread 線程執(zhí)行完畢之后,main 線程解除阻塞,繼續(xù)執(zhí)行下去。
運(yùn)行結(jié)果:
補(bǔ)充: main 中調(diào)用 join() 方法,有以下可能性:
? ? ? ? 1.0 如果 t 線程此時(shí)已經(jīng)結(jié)束了,此時(shí) join() 方法就會(huì)立即返回。
? ? ? ? 2.0 如果 t 線程此時(shí)還沒有結(jié)束,此時(shí) main 就會(huì)阻塞等待,一直等待到 t 線程結(jié)束之后,main 線程才會(huì)接觸阻塞,繼續(xù)執(zhí)行。
? ? ? ? 3.0 如果調(diào)用等待阻塞的線程對(duì)象還沒創(chuàng)建 pcb 的時(shí)候(即還沒 start() 的時(shí)候),那么調(diào)用 join() 方法的線程會(huì)直接解除阻塞。
? ? ? ? 1.1.1 main 線程中等待多個(gè)線程
? ? ? ? 在 main 線程中多次調(diào)用 join() 方法時(shí),先執(zhí)行 t1.join(),如果 t1 還沒結(jié)束,main 繼續(xù)阻塞等待,t1 結(jié)束之后,繼續(xù)執(zhí)行 t2.join() 方法,再等待 t2 結(jié)束。注意,t1 與 t2 之間同樣是搶占式執(zhí)行隨機(jī)調(diào)度,所以先后順序?qū)τ?main 線程來說沒有什么區(qū)別。
代碼如下:
public class demo2 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("正在執(zhí)行 t1 線程"); } }); Thread t2 = new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("正在執(zhí)行 t2 線程"); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("正在執(zhí)行 main 線程"); } }
運(yùn)行結(jié)果:
? ? ? ? 1.1.2 main 線程等待 t2?線程且t2?線程等待 t1?線程
? ? ? ? 這種情況是按順序執(zhí)行的,大致就是串行執(zhí)行一樣。順序?yàn)椋合纫獔?zhí)行完 t1 再執(zhí)行 t2 最后再執(zhí)行 main 線程。
代碼如下:
public class demo3 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("正在執(zhí)行 t1 線程"); } }); Thread t2 = new Thread(()->{ try { t1.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("正在執(zhí)行 t2 線程"); } }); t1.start(); t2.start(); t2.join(); System.out.println("執(zhí)行 main 線程"); } }
? ? ? ? t1.start() 立即創(chuàng)建 t1 線程,再 t2.start() 創(chuàng)建線程,t1 沒有任何阻塞就會(huì)直接執(zhí)行代碼,而 t2 遇到了阻塞,需要等待 t1 執(zhí)行完畢之后,t2 才會(huì)解除阻塞,同時(shí)由于 main 線程阻塞了,需要等待 t2 執(zhí)行完畢,當(dāng) t2 執(zhí)行完畢之后,main 線程解除阻塞了,執(zhí)行 main 線程中的代碼。
運(yùn)行結(jié)果:
? ? ? ? 1.1.3 其他線程阻塞等待 main 線程
? ? ? ? t1 線程阻塞等待 main 線程執(zhí)行完畢之后,再執(zhí)行 t1 線程。
代碼如下:
public class demo4 { public static void main(String[] args) throws InterruptedException { //拿到當(dāng)前 main 線程對(duì)象 Thread mainThread = Thread.currentThread(); Thread t1 = new Thread(()->{ //在 t1 線程中調(diào)用 join() 方法, //阻塞當(dāng)前 t1 線程,等待 main 線程執(zhí)行完畢 try { mainThread.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("正在執(zhí)行 t1 線程"); } }); t1.start(); for (int i = 0; i < 5; i++) { Thread.sleep(1000); System.out.println("正在執(zhí)行 main 線程"); } } }
運(yùn)行結(jié)果:
? ? ? ? 1.1.4 在指定的時(shí)間內(nèi)阻塞等待
? ? ? ? join() 方法還有一個(gè)重載的版本,可以指定一個(gè)超時(shí)時(shí)間,即 join(long millis),表示當(dāng)前線程最多等待 millis?毫秒,如果超過這個(gè)時(shí)間 thread 線程還沒有執(zhí)行完畢,當(dāng)前線程會(huì)繼續(xù)往下執(zhí)行。簡單來說,即使 thread 這個(gè)線程還沒有結(jié)束,main 線程都不會(huì)繼續(xù)等待了;如果 thread 在規(guī)定的時(shí)間內(nèi)提前結(jié)束,那么 main 也會(huì)提前解除阻塞。
代碼如下:
public class demo5 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ for (int i = 0; i < 1000; i++) { System.out.println("正在執(zhí)行 thread 線程"); } }); thread.start(); //等待 0.1 s 就解除阻塞 main 線程,即不會(huì)繼續(xù)等待了 thread.join(1000); System.out.println("正在執(zhí)行 main"); } }
運(yùn)行結(jié)果:
? ? ? ? 1.2?線程等待 - Thread.sleep() 方法
????????是一個(gè)靜態(tài)方法,它使當(dāng)前線程暫停執(zhí)行一段時(shí)間。該方法接受一個(gè)以毫秒為單位的時(shí)間參數(shù),指定線程暫停的時(shí)間長度。在這段時(shí)間內(nèi),線程不會(huì)執(zhí)行任何操作,但是線程的狀態(tài)仍然是 Runnable 狀態(tài),可以隨時(shí)被調(diào)度器調(diào)度執(zhí)行。
????????需要注意的是,Thread.sleep() 方法不是真正意義上的線程等待,它只是讓線程暫停執(zhí)行一段時(shí)間,不會(huì)釋放鎖或資源。在實(shí)際開發(fā)中,應(yīng)根據(jù)具體需求選擇合適的線程等待機(jī)制,以確保程序的正確性和效率。
代碼如下:
public class demo6 { public static void main(String[] args) { Thread thread = new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("正在執(zhí)行 thread 線程"); } }); thread.start(); } }
運(yùn)行結(jié)果:
? ? ? ? 每相隔 1 秒就會(huì)輸出一次。
? ? ? ? 需要注意的是,這里的 Thread.sleep() 方法是受查異常,且 run() 是重寫父類的方法,該 run() 方法的方法名、參數(shù)列表、聲明異常都需要與父類保持一致,因此這里不能聲明異常,只能捕獲異常處理。
? ? ? ? 2.0 線程狀態(tài)
? ? ? ? 在 Java 中主要包括六種不同的狀態(tài)。
? ? ? ? 2.1 新建狀態(tài) - NEW
? ? ? ? 當(dāng)創(chuàng)建一個(gè)線程對(duì)象時(shí),線程處于新建狀態(tài),此時(shí)線程對(duì)象已經(jīng)創(chuàng)建好了,但是還沒調(diào)用 start() 方法啟動(dòng)線程,因此線程還沒被創(chuàng)建出來。
? ? ? ? 2.2 就緒狀態(tài) - Runnable
? ? ? ? 有兩種情況都屬于就緒狀態(tài):1)還沒運(yùn)行,就緒狀態(tài)。但是線程已經(jīng)準(zhǔn)備好運(yùn)行了,只等待被 CPU 調(diào)度執(zhí)行。2)線程正在被 CPU 調(diào)度執(zhí)行中,運(yùn)行狀態(tài)。總而言之,無論是就緒狀態(tài)還是運(yùn)行狀態(tài)在 Java 中都屬于 Runnable 狀態(tài),即就緒狀態(tài)。
? ? ? ? 2.3 終止?fàn)顟B(tài) -Terminated
? ? ? ? 線程執(zhí)行完任務(wù)后或者出現(xiàn)異常導(dǎo)致線程終止時(shí),線程進(jìn)入終止?fàn)顟B(tài)。在終止?fàn)顟B(tài)下,線程不再執(zhí)行任務(wù)。
? ? ? ? 2.4 等待狀態(tài) - Waiting
? ? ? ? 線程進(jìn)入等待狀態(tài)通常時(shí)因?yàn)檎{(diào)用了 thread.join() 方法等等。
代碼如下:
public class demo7 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ while (true){ System.out.println(1); } }); thread.start(); thread.join(); System.out.println("正在執(zhí)行 main 線程"); } }
演示線程等待:
? ? ? ? main 線程調(diào)用了 thread.join() 方法阻塞等待 thread 線程,又因?yàn)?thread 還當(dāng)前為止還沒結(jié)束,?所以當(dāng)前 main 線程被阻塞了,因此 main 狀態(tài)為 Waiting 狀態(tài)。對(duì)于 thread 線程來說,目前的狀態(tài)為 Runnable 狀態(tài)。
? ? ? ? 2.5 超時(shí)等待狀態(tài) - Time_Waiting
? ? ? ? 線程調(diào)用帶有超時(shí)參數(shù)的等待方法,比如 Thread.sleep(long millis) 等待方法。線程會(huì)進(jìn)入超時(shí)等待狀態(tài)下,線程會(huì)等待一段時(shí)間后自動(dòng)恢復(fù)到就緒狀態(tài)。
代碼如下:
public class demo8 { public static void main(String[] args) { Thread thread = new Thread(()->{ try { Thread.sleep(9000000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("正在執(zhí)行 thread 線程"); }); thread.start(); System.out.println("正在執(zhí)行 main 線程"); } }
演示超時(shí)等待:
? ? ? ? 2.6 阻塞狀態(tài) - Blocked
? ? ? ? 線程在特定情況下,會(huì)進(jìn)入阻塞狀態(tài),比如調(diào)用了 Thread.sleep() 方法或者加鎖。在線程阻塞狀態(tài)下,線程暫時(shí)停止執(zhí)行,直到滿足特定條件后,才能繼續(xù)執(zhí)行。
代碼如下:
死鎖狀態(tài):兩個(gè)線程兩把鎖
public class demo10 { public static void main(String[] args) { Object o1 = new Object(); Object o2 = new Object(); Thread t1 = new Thread(()->{ synchronized (o1){ try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (o2){ System.out.println("正在執(zhí)行 t1 線程"); } } }); Thread t2 = new Thread(()->{ synchronized (o2){ try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (o1){ System.out.println("正在執(zhí)行 t2 線程"); } } }); t1.start(); t2.start(); } }
演示阻塞狀態(tài):
? ? ? ? 2.7 線程狀態(tài)之間的相互轉(zhuǎn)換圖
文章來源:http://www.zghlxwxcb.cn/news/detail-854105.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-854105.html
到了這里,關(guān)于JavaEE 初階篇-深入了解多線程等待與多線程狀態(tài)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!