偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Java多次啟動一個線程究竟會發(fā)生什么?程序到底會不會崩?大部分程序員理解錯誤?。?/h1>

開發(fā) 前端
Java 的線程是不允許啟動兩次的,第二次調(diào)用必然會拋出 IllegalThreadStateException,這是一種運(yùn)行時(shí)異常,表示非法的線程狀態(tài)異常。

今天給大家分享的面試題是:一個線程調(diào)用兩次start()方法會出現(xiàn)什么現(xiàn)象?這道面試題是一道關(guān)于多線程的基礎(chǔ)面試題,很多小伙伴對這個面試題不太了解,其實(shí),如果你看過JDK中關(guān)于Thread類的源碼,那這道面試題對你來說就能過輕松應(yīng)對了。

手寫RPC框架視頻錄制中,發(fā)布地址:https://space.bilibili.com/517638832/channel/collectiondetail?sid=4186280

今天,我們就一起來聊聊這道面試題,以及面試官問這道題的面試分析拓展知識。

優(yōu)質(zhì)回答

Java 的線程是不允許啟動兩次的,第二次調(diào)用必然會拋出 IllegalThreadStateException,這是一種運(yùn)行時(shí)異常,表示非法的線程狀態(tài)異常。

關(guān)于線程生命周期的不同狀態(tài),在 Java 5 以后,線程狀態(tài)被明確定義在其公共內(nèi)部枚舉類型 java.lang.Thread.State 中,分別是:

  • 新建(NEW),表示線程被創(chuàng)建出來還沒真正啟動的狀態(tài),可以認(rèn)為它是個 Java 內(nèi)部狀態(tài)。
  • 就緒(RUNNABLE),表示該線程已經(jīng)在 JVM 中執(zhí)行,當(dāng)然由于執(zhí)行需要計(jì)算資源,它可能是正在運(yùn)行,也可能還在等待系統(tǒng)分配給它 CPU 片段,在就緒隊(duì)列里面排隊(duì)。
  • 在其他一些分析中,會額外區(qū)分一種狀態(tài) RUNNING,但是從 Java API 的角度,并不能表示出來。
  • 阻塞(BLOCKED),這個狀態(tài)和我們前面兩講介紹的同步非常相關(guān),阻塞表示線程在等待 Monitor lock。比如,線程試圖通過 synchronized 去獲取某個鎖,但是其他線程已經(jīng)獨(dú)占了,那么當(dāng)前線程就會處于阻塞狀態(tài)。
  • 等待(WAITING),表示正在等待其他線程采取某些操作。一個常見的場景是類似生產(chǎn)者消費(fèi)者模式,發(fā)現(xiàn)任務(wù)條件尚未滿足,就讓當(dāng)前消費(fèi)者線程等待(wait),另外的生產(chǎn)者線程去準(zhǔn)備任務(wù)數(shù)據(jù),然后通過類似 notify 等動作,通知消費(fèi)線程可以繼續(xù)工作了。Thread.join() 也會令線程進(jìn)入等待狀態(tài)。
  • 計(jì)時(shí)等待(TIMED_WAIT),其進(jìn)入條件和等待狀態(tài)類似,但是調(diào)用的是存在超時(shí)條件的方法,比如 wait 或 join 等方法的指定超時(shí)版本,如下面示例:
public final native void wait(long timeout) throws InterruptedException;
  • 終止(TERMINATED),不管是意外退出還是正常執(zhí)行結(jié)束,線程已經(jīng)完成使命,終止運(yùn)行,也有人把這個狀態(tài)叫作死亡。

在第二次調(diào)用 start() 方法的時(shí)候,線程可能處于終止或者其他(非 NEW)狀態(tài),但是不論如何,都是不可以再次啟動的。

面試分析

今天的面試題看似簡單,實(shí)則是對面試者基礎(chǔ)知識的考察,很多大廠在面試時(shí),很重視面試者對基礎(chǔ)知識的掌握程度,往往這些基礎(chǔ)知識是大家最容易忽視的。

知識拓展

線程的通用生命周期

線程在運(yùn)行的過程中,會經(jīng)歷幾種狀態(tài)之間的轉(zhuǎn)換,而線程在這幾種狀態(tài)之間的轉(zhuǎn)換流程,基本上就構(gòu)成了線程的生命周期。本小節(jié),就簡單介紹下線程的通用生命周期。

線程的通用生命周期總體上可以分為五種狀態(tài),分別為:初始狀態(tài)、可運(yùn)行狀態(tài)、運(yùn)行狀態(tài)、休眠狀態(tài)和終止?fàn)顟B(tài)

圖片圖片

可以看出,線程的通用生命周期可以分為初始狀態(tài)、可運(yùn)行狀態(tài)、運(yùn)行狀態(tài)、休眠狀態(tài)和終止?fàn)顟B(tài)五種狀態(tài)。

(1)初始狀態(tài):初始狀態(tài)比較特殊,這種狀態(tài)屬于編程語言層面特有的狀態(tài),處于初始狀態(tài)的線程只是線程在編程語言層面被創(chuàng)建了,但是在操作系統(tǒng)層面,并沒有真正的創(chuàng)建線程。

(2)可運(yùn)行狀態(tài):在操作系統(tǒng)層面,線程被真正的創(chuàng)建,并且可以分配CPU執(zhí)行。

(3)運(yùn)行狀態(tài):處于運(yùn)行狀態(tài)的線程已經(jīng)獲取到CPU資源,正在運(yùn)行。

(4)休眠狀態(tài):線程正在等待某個事件的發(fā)生(例如等待I/O事件的完成),或者調(diào)用了一個阻塞的API正處于阻塞狀態(tài)(例如以阻塞的方式讀寫文件等),此時(shí)的線程處于休眠狀態(tài)。

(5)終止?fàn)顟B(tài):線程正常運(yùn)行結(jié)束或者出現(xiàn)異常,就會進(jìn)入終止?fàn)顟B(tài)。

線程的通用生命周期中各狀態(tài)之間的轉(zhuǎn)換關(guān)系如下所示。

(1)初始狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài):處于初始狀態(tài)的線程,實(shí)際上并沒有在操作系統(tǒng)中創(chuàng)建對應(yīng)的線程,當(dāng)在操作系統(tǒng)中創(chuàng)建了對應(yīng)的線程時(shí),此時(shí)線程就會從初始狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

(2)可運(yùn)行狀態(tài)轉(zhuǎn)換成運(yùn)行狀態(tài):如果操作系統(tǒng)中存在空閑的CPU資源,則操作系統(tǒng)會將空閑的CPU資源分配給一個處于可運(yùn)行狀態(tài)的線程,處于可運(yùn)行狀態(tài)的線程獲得CPU資源后就會轉(zhuǎn)換成運(yùn)行狀態(tài)。也就是說,處于可運(yùn)行狀態(tài)的線程,被操作系統(tǒng)調(diào)度獲取到CPU資源后,就會從可運(yùn)行狀態(tài)轉(zhuǎn)換成運(yùn)行狀態(tài)。

(3)運(yùn)行狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài):當(dāng)正在運(yùn)行的線程CPU時(shí)間片用完時(shí),就會從運(yùn)行狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

(4)運(yùn)行狀態(tài)轉(zhuǎn)換成休眠狀態(tài):處于運(yùn)行狀態(tài)的線程如果等待某個事件的發(fā)生(例如,等待I/O事件的完成),或者調(diào)用了一個阻塞的API(例如,以阻塞的方式讀寫文件等),此時(shí)處于運(yùn)行狀態(tài)的線程就會釋放CPU的資源,從運(yùn)行狀態(tài)轉(zhuǎn)換成休眠狀態(tài)。

(5)休眠狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài):如果處于休眠狀態(tài)的線程等待的事件已經(jīng)發(fā)生(例如,等待的I/O事件已經(jīng)完成),或者調(diào)用的阻塞API已經(jīng)完成操作(例如,以阻塞的方式讀寫文件已經(jīng)完成),則線程就會從休眠狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

(6)運(yùn)行狀態(tài)轉(zhuǎn)換成終止?fàn)顟B(tài):處于運(yùn)行狀態(tài)的線程正常運(yùn)行結(jié)束,或者出現(xiàn)異常,就會從運(yùn)行狀態(tài)轉(zhuǎn)換成終止?fàn)顟B(tài)。處于終止?fàn)顟B(tài)的線程,不會再轉(zhuǎn)換成其他的狀態(tài),線程的生命周期也就結(jié)束了。

注意:在線程的通用生命周期中,只有處于運(yùn)行狀態(tài)的線程可以直接轉(zhuǎn)換成終止?fàn)顟B(tài)和休眠狀態(tài),處于其他狀態(tài)的線程都不能直接轉(zhuǎn)換成終止?fàn)顟B(tài)和休眠狀態(tài)。處于休眠狀態(tài)的線程只能直接轉(zhuǎn)換成可運(yùn)行狀態(tài),不能直接轉(zhuǎn)換成其他狀態(tài)。

Java中線程的生命周期

在Java中,線程的生命周期主要包括:初始化狀態(tài)、可運(yùn)行狀態(tài)、阻塞狀態(tài)、等待狀態(tài)、超時(shí)等待狀態(tài)和終止?fàn)顟B(tài)。其中,可運(yùn)行狀態(tài)又包括運(yùn)行狀態(tài)和就緒狀態(tài)。

圖片圖片

可以看出,在Java的線程生命周期中,總體上包含初始化狀態(tài)、可運(yùn)行狀態(tài)、等待狀態(tài)、超時(shí)等待狀態(tài)、阻塞狀態(tài)和終止?fàn)顟B(tài)六種狀態(tài)。

(1)初始化狀態(tài):線程在Java中被創(chuàng)建,但是還沒有調(diào)用線程對象的start()方法,也就是說,還沒有創(chuàng)建操作系統(tǒng)層面對應(yīng)的線程。

(2)可運(yùn)行狀態(tài):Java線程生命周期中的可運(yùn)行狀態(tài),包含操作系統(tǒng)中線程的運(yùn)行狀態(tài)和就緒狀態(tài)。

(3)等待狀態(tài):處于等待狀態(tài)的線程需要等待其他線程對當(dāng)前線程進(jìn)行通知或者中斷等操作,從而進(jìn)入下一個線程狀態(tài)。

(4)超時(shí)等待狀態(tài):處于超時(shí)等待狀態(tài)的線程需要在指定的時(shí)間內(nèi),等待其他線程對當(dāng)前線程進(jìn)行通知或者中斷等操作。如果在指定的時(shí)間內(nèi),存在其他線程對當(dāng)前線程進(jìn)行通知或者中斷等操作,則當(dāng)前線程進(jìn)入下一個狀態(tài)。否則超過指定的時(shí)間,當(dāng)前線程也會進(jìn)入下一個狀態(tài)。

(5)阻塞狀態(tài):處于阻塞狀態(tài)的線程需要等待其他線程釋放鎖,或者等待進(jìn)入synchronized臨界區(qū)。

(6)終止?fàn)顟B(tài):表示當(dāng)前線程執(zhí)行完畢,包括正常執(zhí)行結(jié)束和異常退出。

Java的線程生命周期中的可運(yùn)行狀態(tài),涵蓋了運(yùn)行狀態(tài)和就緒狀態(tài)。

(1)運(yùn)行狀態(tài):對應(yīng)操作系統(tǒng)中的運(yùn)行狀態(tài)。

(2)就緒狀態(tài):對應(yīng)操作系統(tǒng)中的就緒狀態(tài)。

在Java的線程生命周期中,各狀態(tài)之間的轉(zhuǎn)換關(guān)系如下所示。

1.初始化狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)的場景

在Java層面,調(diào)用線程對象的start()方法,會在操作系統(tǒng)層面創(chuàng)建對應(yīng)的線程,此時(shí),線程的狀態(tài)就會從初始化狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

2.可運(yùn)行狀態(tài)與等待狀態(tài)互相轉(zhuǎn)換的場景一

(1)線程a調(diào)用synchronized(obj)獲取到對象鎖后,調(diào)用obj.wait()方法時(shí),線程a的狀態(tài)會從可運(yùn)行狀態(tài)轉(zhuǎn)換成等待狀態(tài)。

(2)在滿足(1)時(shí),此時(shí)線程b調(diào)用synchronized(obj)獲取到對象鎖后,調(diào)用obj.notify()方法、obj.notifyAll()方法、a.interrupt()方法,此時(shí)會有兩種情況,如下所示。

l 線程a競爭鎖成功,則線程a會由等待狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

l 線程a競爭鎖失敗,則線程a會由等待狀態(tài)轉(zhuǎn)換成阻塞狀態(tài)。

3.可運(yùn)行狀態(tài)與等待狀態(tài)互相轉(zhuǎn)換的場景二

(1)線程a調(diào)用線程b的join()方法時(shí),線程a會由可運(yùn)行狀態(tài)轉(zhuǎn)換成等待狀態(tài)。

(2)在滿足(1)時(shí),線程b運(yùn)行結(jié)束,或者調(diào)用了線程a的interrupt()方法,則線程a會從等待狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

4.可運(yùn)行狀態(tài)與等待狀態(tài)互相轉(zhuǎn)換的場景三

(1)線程a調(diào)用LockSupport.park()方法時(shí),線程a會從可運(yùn)行狀態(tài)轉(zhuǎn)換成等待狀態(tài)。

(2)在滿足(1)時(shí),其他線程調(diào)用LockSupport.unpark(a),或者調(diào)用線程a的interrupt()方法,線程a會從等待狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

5.可運(yùn)行狀態(tài)與超時(shí)等待狀態(tài)互相轉(zhuǎn)換的場景一

(1)線程a調(diào)用synchronized(obj)獲取到對象鎖后,調(diào)用obj.wait(long n)方法,則線程a會從可運(yùn)行狀態(tài)轉(zhuǎn)換成超時(shí)等待狀態(tài)。

(2)在滿足(1)時(shí),線程a的等待時(shí)間超過了n毫秒,或者線程b調(diào)用synchronized(obj)獲取到對象鎖后,調(diào)用obj.notify()方法、obj.notifyAll()方法、a.interrupt()方法,此時(shí)會有兩種情況,如下所示。

l 線程a競爭鎖成功,則線程a會由超時(shí)等待狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

l 線程a競爭鎖失敗,則線程a會由超時(shí)等待狀態(tài)轉(zhuǎn)換成阻塞狀態(tài)。

6.可運(yùn)行狀態(tài)與超時(shí)等待狀態(tài)互相轉(zhuǎn)換的場景二

(1)線程a調(diào)用Thread.sleep(long n)方法,則線程a會從可運(yùn)行狀態(tài)轉(zhuǎn)換成超時(shí)等待狀態(tài)。

(2)在滿足(1)時(shí),線程a的等待時(shí)間超過n毫秒,則線程a會從超時(shí)等待狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

7.可運(yùn)行狀態(tài)與超時(shí)等待狀態(tài)互相轉(zhuǎn)換的場景三

(1)線程a調(diào)用了線程b的join(long n)方法時(shí),線程a會從可運(yùn)行狀態(tài)轉(zhuǎn)換成超時(shí)等待狀態(tài)。

(2)在滿足(1)時(shí),線程a的等待時(shí)間超過n毫秒,或者線程b運(yùn)行結(jié)束,或者調(diào)用了線程a的interrupt()方法,線程a會從超時(shí)等待狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

8.可運(yùn)行狀態(tài)與超時(shí)等待狀態(tài)互相轉(zhuǎn)換的場景四

(1)線程a調(diào)用Locksupport.parkNanos(long nacos)方法,或者調(diào)用LockSupport.parkUntil(long millis)方法時(shí),線程a會從可運(yùn)行狀態(tài)轉(zhuǎn)換成超時(shí)等待狀態(tài)。

(2)在滿足(1)時(shí),其他線程調(diào)用LockSupport.unpark(a),或者調(diào)用線程a的interrupt()方法,或者線程a等待超時(shí),則線程a會從超時(shí)等待狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

9.可運(yùn)行狀態(tài)與阻塞狀態(tài)互相轉(zhuǎn)換的場景一

(1)線程a與線程b共同爭搶同一個悲觀鎖,線程b爭搶成功,則線程a會從可運(yùn)行狀態(tài)轉(zhuǎn)換成阻塞狀態(tài)。

(2)在滿足(1)時(shí),線程b釋放鎖時(shí),線程a獲取到鎖,則線程a會從阻塞狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。

10.可運(yùn)行狀態(tài)與阻塞狀態(tài)互相轉(zhuǎn)換的場景二

(1)線程a調(diào)用synchronized(obj)獲取對象鎖時(shí),競爭失敗,則線程a會從可運(yùn)行狀態(tài)轉(zhuǎn)換成阻塞狀態(tài)。

(2)在滿足(1)時(shí),調(diào)用synchronized(obj)獲取對象鎖時(shí)競爭成功的線程,執(zhí)行同步代碼塊完畢,就會喚醒所有阻塞在obj對象上的線程,這些被喚醒的線程會重新競爭,如果線程a競爭成功,則線程a會從阻塞狀態(tài)轉(zhuǎn)換成可運(yùn)行狀態(tài)。如果線程a競爭失敗,則線程a繼續(xù)保持阻塞狀態(tài)。

11.可運(yùn)行狀態(tài)轉(zhuǎn)換成終止?fàn)顟B(tài)的場景

線程a正常執(zhí)行結(jié)束,或者由于某種原因異常退出,線程a就會從可運(yùn)行狀態(tài)轉(zhuǎn)換成終止?fàn)顟B(tài)。

如果一個線程轉(zhuǎn)換成終止?fàn)顟B(tài),那么就標(biāo)注著這個線程已經(jīng)運(yùn)行結(jié)束,不能再次轉(zhuǎn)換成其他狀態(tài)。

責(zé)任編輯:武曉燕 來源: 冰河技術(shù)
相關(guān)推薦

2020-04-15 16:07:01

程序員技術(shù)數(shù)據(jù)

2019-11-20 10:12:32

程序員 東漢崗位

2019-06-12 10:35:49

程序員高效工具開源

2019-09-12 09:56:13

程序員技能開發(fā)者

2019-10-11 10:05:30

程序員固態(tài)硬盤Google

2021-11-30 22:59:28

程序員IT架構(gòu)師

2020-09-29 08:33:17

基站信號健康

2020-03-03 18:59:47

CDN緩存程序員

2019-11-24 19:34:04

HTTP長連接短連接

2011-11-24 14:20:24

Java

2019-08-09 11:25:01

Java虛擬機(jī)Java程序員

2020-06-08 15:15:26

程序員擺地?cái)?/a>技術(shù)

2020-05-11 08:36:21

程序員工作生活

2022-09-06 11:33:24

系統(tǒng)程序員

2009-03-20 10:19:12

程序員編程職場

2020-10-05 21:13:37

程序員技能開發(fā)者

2020-02-22 21:51:43

程序員Microsoft SServerSQL

2020-04-03 08:42:08

Servelt3程序員Tomcat

2022-04-20 11:41:45

Kafka數(shù)據(jù)解決方案

2024-07-03 09:15:33

MySQL表達(dá)式索引
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號