欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解答為什么 Java 線程沒有Running狀態(tài)

 更新時間:2021年09月17日 11:49:00   作者:IT老哥  
Java 線程沒有Running狀態(tài)指的是一個在 JVM 中執(zhí)行 的線程處于的狀態(tài),本文小編將為大家詳解一二,需要的朋友可以參考下面文章具體內(nèi)容

Java虛擬機(jī)層面所暴露給我們的狀態(tài),與操作系統(tǒng)底層的線程狀態(tài)是兩個不同層面的事。具體而言,這里說的 Java 線程狀態(tài)均來自于 Thread 類下的 State 這一內(nèi)部枚舉類中所定義的狀態(tài):

一、什么是 RUNNABLE?

直接看它的 Javadoc 中的說明:

一個在 JVM 中執(zhí)行 的線程處于這一狀態(tài)中。(A thread executing in the Java virtual machine is in this state.

而傳統(tǒng)的進(jìn)(線)程狀態(tài)一般劃分如下:

注:這里的進(jìn)程指早期的單線程 進(jìn)程,這里所謂進(jìn)程狀態(tài)實質(zhì)就是線程狀態(tài)。

那么 runnable 與圖中的 ready running 區(qū)別在哪呢?

二、與傳統(tǒng)的ready狀態(tài)的區(qū)別

更具體點(diǎn),javadoc 中是這樣說的:

處于 runnable 狀態(tài)下的線程正在 Java 虛擬機(jī)中執(zhí)行,但它可能正在等待 來自于操作系統(tǒng)的其它資源,比如處理器。

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 狀態(tài)實質(zhì)上是包括了 ready 狀態(tài)的。

甚至還可能有包括上圖中的 waiting 狀態(tài)的部分細(xì)分狀態(tài),在后面我們將會看到這一點(diǎn)。

三、與傳統(tǒng)的running狀態(tài)的區(qū)別

有人常覺得 Java 線程狀態(tài)中還少了個 running 狀態(tài),這其實是把兩個不同層面的狀態(tài)混淆了。對 Java 線程狀態(tài)而言,不存在所謂的running 狀態(tài),它的 runnable 狀態(tài)包含了 running 狀態(tài)。

我們可能會問,為何 JVM 中沒有去區(qū)分這兩種狀態(tài)呢?

現(xiàn)在的時分 (time-sharing)多任務(wù) (multi-task)操作系統(tǒng)架構(gòu)通常都是用所謂的“時間分片 (time quantum or time slice)”方式進(jìn)行搶占式 (preemptive)輪轉(zhuǎn)調(diào)度(round-robin式)。

更復(fù)雜的可能還會加入優(yōu)先級(priority)的機(jī)制。

這個時間分片通常是很小的,一個線程一次最多只能在 cpu 上運(yùn)行比如10-20ms 的時間(此時處于 running 狀態(tài)),也即大概只有0.01秒這一量級,時間片用后就要被切換下來放入調(diào)度隊列的末尾等待再次調(diào)度。(也即回到 ready 狀態(tài))

注:如果期間進(jìn)行了 I/O 的操作還會導(dǎo)致提前釋放時間分片,并進(jìn)入等待隊列。

又或者是時間分片沒有用完就被搶占,這時也是回到 ready 狀態(tài)。

這一切換的過程稱為線程的上下文切換 (context switch),當(dāng)然 cpu 不是簡單地把線程踢開就完了,還需要把被相應(yīng)的執(zhí)行狀態(tài)保存到內(nèi)存中以便后續(xù)的恢復(fù)執(zhí)行。

顯然,10-20ms 對人而言是很快的,

不計切換開銷(每次在1ms 以內(nèi)),相當(dāng)于1秒內(nèi)有50-100次切換。事實上時間片經(jīng)常沒用完,線程就因為各種原因被中斷,實際發(fā)生的切換次數(shù)還會更多。

也這正是單核 *CPU 上實現(xiàn)所謂的“ 并發(fā)*(concurrent)”的基本原理,但其實是快速切換所帶來的假象,這有點(diǎn)類似一個手腳非??斓碾s耍演員可以讓好多個球同時在空中運(yùn)轉(zhuǎn)那般。

時間分片也是可配置的,如果不追求在多個線程間很快的響應(yīng),也可以把這個時間配置得大一點(diǎn),以減少切換帶來的開銷。

如果是多核CPU,才有可能實現(xiàn)真正意義上的并發(fā),這種情況通常也叫并行 (pararell),不過你可能也會看到這兩詞會被混著用,這里就不去糾結(jié)它們的區(qū)別了。

通常,Java的線程狀態(tài)是服務(wù)于監(jiān)控的,如果線程切換得是如此之快,那么區(qū)分 ready running 就沒什么太大意義了。

當(dāng)你看到監(jiān)控上顯示是 running 時,對應(yīng)的線程可能早就被切換下去了,甚至又再次地切換了上來,也許你只能看到 ready 與 running 兩個狀態(tài)在快速地閃爍。

當(dāng)然,對于精確的性能評估而言,獲得準(zhǔn)確的 running 時間是有必要的。

現(xiàn)今主流的 JVM 實現(xiàn)都把 Java 線程一一映射到操作系統(tǒng)底層的線程上,把調(diào)度委托給了操作系統(tǒng),我們在虛擬機(jī)層面看到的狀態(tài)實質(zhì)是對底層狀態(tài)的映射及包裝。JVM 本身沒有做什么實質(zhì)的調(diào)度,把底層的 ready running 狀態(tài)映射上來也沒多大意義,因此,統(tǒng)一成為runnable 狀態(tài)是不錯的選擇。

我們將看到,Java 線程狀態(tài)的改變通常只與自身顯式引入的機(jī)制有關(guān)。

四、當(dāng)I/O阻塞時

我們知道傳統(tǒng)的I/O都是阻塞式(blocked)的,原因是I/O操作比起cpu來實在是太慢了,可能差到好幾個數(shù)量級都說不定。如果讓 cpu 去等I/O 的操作,很可能時間片都用完了,I/O 操作還沒完成呢,不管怎樣,它會導(dǎo)致 cpu 的利用率極低。

所以,解決辦法就是:一旦線程中執(zhí)行到 I/O 有關(guān)的代碼,相應(yīng)線程立馬被切走,然后調(diào)度 ready 隊列中另一個線程來運(yùn)行。

這時執(zhí)行了 I/O 的線程就不再運(yùn)行,即所謂的被阻塞了。它也不會被放到調(diào)度隊列中去,因為很可能再次調(diào)度到它時,I/O 可能仍沒有完成。

線程會被放到所謂的等待隊列中,處于上圖中的 waiting 狀態(tài):

當(dāng)然了,我們所謂阻塞只是指這段時間 cpu 暫時不會理它了,但另一個部件比如硬盤則在努力地為它服務(wù)。cpu 與硬盤間是并發(fā)的。如果把線程視作為一個 job,這一 job 由 cpu 與硬盤交替協(xié)作完成,當(dāng)在 cpu 上是 waiting 時,在硬盤上卻處于 running,只是我們在操作系統(tǒng)層面討論線程狀態(tài)時通常是圍繞著 cpu 這一中心去述說的。

而當(dāng) I/O 完成時,則用一種叫中斷 (interrupt)的機(jī)制來通知 cpu:

也即所謂的“中斷驅(qū)動 (interrupt-driven)”,現(xiàn)代操作系統(tǒng)基本都采用這一機(jī)制。

某種意義上,這也是控制反轉(zhuǎn) (IoC)機(jī)制的一種體現(xiàn),cpu不用反復(fù)去詢問硬盤,這也是所謂的“好萊塢原則”—Don't call us, we will call you.好萊塢的經(jīng)紀(jì)人經(jīng)常對演員們說:“別打電話給我,(有戲時)我們會打電話給你?!?/p>

在這里,硬盤與 cpu 的互動機(jī)制也是類似,硬盤對 cpu 說:”別老來問我 IO 做完了沒有,完了我自然會通知你的“

當(dāng)然了,cpu 還是要不斷地檢查中斷,就好比演員們也要時刻注意接聽電話,不過這總好過不斷主動去詢問,畢竟絕大多數(shù)的詢問都將是徒勞的。

cpu 會收到一個比如說來自硬盤的中斷信號,并進(jìn)入中斷處理例程,手頭正在執(zhí)行的線程因此被打斷,回到 ready 隊列。而先前因 I/O 而waiting 的線程隨著 I/O 的完成也再次回到 ready 隊列,這時 cpu 可能會選擇它來執(zhí)行。

另一方面,所謂的時間分片輪轉(zhuǎn)本質(zhì)上也是由一個定時器定時中斷來驅(qū)動的,可以使線程從 running 回到 ready 狀態(tài):

比如設(shè)置一個10ms 的倒計時,時間一到就發(fā)一個中斷,好像大限已到一樣,然后重置倒計時,如此循環(huán)。

與 cpu 正打得火熱的線程可能不情愿聽到這一中斷信號,因為它意味著這一次與 cpu 纏綿的時間又要到頭了......奴為出來難,何日君再來?

現(xiàn)在我們再看一下 Java 中定義的線程狀態(tài),嘿,它也有 BLOCKED(阻塞),也有 WAITING(等待),甚至它還更細(xì),還有TIMED_WAITING:

現(xiàn)在問題來了,進(jìn)行阻塞式 I/O 操作時,Java 的線程狀態(tài)究竟是什么?是 BLOCKED?還是 WAITING?

可能你已經(jīng)猜到,既然放到 RUNNABLE 這一主題下討論,其實狀態(tài)還是 RUNNABLE。我們也可以通過一些測試來驗證這一點(diǎn):

`@Test`
`public void testInBlockedIOState() throws InterruptedException {`
 `Scanner in = new Scanner(System.in);`
 `// 創(chuàng)建一個名為“輸入輸出”的線程t`
 `Thread t = new Thread(new Runnable() {`
 `@Override`
 `public void run() {`
 `try {`
 `// 命令行中的阻塞讀`
 `String input = in.nextLine();`
 `System.out.println(input);`
 `} catch (Exception e) {`
 `e.printStackTrace();`
 `} finally {`
 `IOUtils.closeQuietly(in);`
 `}`
 `}`
 `}, "輸入輸出"); // 線程的名字`
 `// 啟動`
 `t.start();`
 `// 確保run已經(jīng)得到執(zhí)行`
 `Thread.sleep(100);`
 `// 狀態(tài)為RUNNABLE`
 `assertThat(t.getState()).isEqualTo(Thread.State.RUNNABLE);`
`}`

在最后的語句上加一斷點(diǎn),監(jiān)控上也反映了這一點(diǎn):

網(wǎng)絡(luò)阻塞時同理,比如socket.accept,我們說這是一個“阻塞式(blocked)”式方法,但線程狀態(tài)還是 RUNNABLE。

`@Test`
`public void testBlockedSocketState() throws Exception {`
 `Thread serverThread = new Thread(new Runnable() {`
 `@Override`
 `public void run() {`
 `ServerSocket serverSocket = null;`
 `try {`
 `serverSocket = new ServerSocket(10086);`
 `while (true) {`
 `// 阻塞的accept方法`
 `Socket socket = serverSocket.accept();`
 `// TODO`
 `}`
 `} catch (IOException e) {`
 `e.printStackTrace();`
 `} finally {`
 `try {`
 `serverSocket.close();`
 `} catch (IOException e) {`
 `e.printStackTrace();`
 `}`
 `}`
 `}`
 `}, "socket線程"); // 線程的名字`
 `serverThread.start();`
 `// 確保run已經(jīng)得到執(zhí)行`
 `Thread.sleep(500);`
 `// 狀態(tài)為RUNNABLE`
 `assertThat(serverThread.getState()).isEqualTo(Thread.State.RUNNABLE);`
`}`

監(jiān)控顯示:

當(dāng)然,Java 很早就引入了所謂 nio(新的IO)包,至于用 nio 時線程狀態(tài)究竟是怎樣的,這里就不再一一具體去分析了。

至少我們看到了,進(jìn)行傳統(tǒng)上的 IO 操作時,口語上我們也會說“阻塞”,但這個“阻塞”與線程的 BLOCKED 狀態(tài)是兩碼事!

五、如何看待RUNNABLE狀態(tài)?

首先還是前面說的,注意分清兩個層面:

虛擬機(jī)是騎在你操作系統(tǒng)上面的,身下的操作系統(tǒng)是作為某種資源為滿足虛擬機(jī)的需求而存在的。

當(dāng)進(jìn)行阻塞式的 IO 操作時,或許底層的操作系統(tǒng)線程確實處在阻塞狀態(tài),但我們關(guān)心的是 JVM 的線程狀態(tài)。

JVM 并不關(guān)心底層的實現(xiàn)細(xì)節(jié),什么時間分片也好,什么 IO 時就要切換也好,它并不關(guān)心。

前面說到,“處于 runnable 狀態(tài)下的線程正在* Java 虛擬機(jī)中執(zhí)行,但它 可能正在等待*來自于操作系統(tǒng)的其它資源,比如處理器?!?/p>

JVM 把那些都視作資源,cpu 也好,硬盤,網(wǎng)卡也罷,有東西在為線程服務(wù),它就認(rèn)為線程在“執(zhí)行”。

你用嘴,用手,還是用什么鳥東西來滿足它的需求,它并不關(guān)心~

處于 IO 阻塞,只是說 cpu 不執(zhí)行線程了,但網(wǎng)卡可能還在監(jiān)聽呀,雖然可能暫時沒有收到數(shù)據(jù):

就好比前臺或保安坐在他們的位置上,可能沒有接待什么人,但你能說他們沒在工作嗎?

所以 JVM 認(rèn)為線程還在執(zhí)行。而操作系統(tǒng)的線程狀態(tài)是圍繞著 cpu 這一核心去述說的,這與 JVM 的側(cè)重點(diǎn)是有所不同的。

前面我們也強(qiáng)調(diào)了“Java 線程狀態(tài)的改變通常只與自身顯式引入的機(jī)制有關(guān)”,如果 JVM 中的線程狀態(tài)發(fā)生改變了,通常是自身機(jī)制引發(fā)的。

比如 synchronize 機(jī)制有可能讓線程進(jìn)入BLOCKED 狀態(tài),sleep,wait等方法則可能讓其進(jìn)入 WATING 之類的狀態(tài)。

它與傳統(tǒng)的線程狀態(tài)的對應(yīng)可以如下來看:

RUNNABLE 狀態(tài)對應(yīng)了傳統(tǒng)的 ready, running 以及部分的 waiting 狀態(tài)。

到此這篇關(guān)于解答為什么 Java 線程沒有Running狀態(tài)的文章就介紹到這了,更多相關(guān)為什么 Java 線程沒有Running狀態(tài)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解SpringBoot啟動類的掃描注解的用法及沖突原則

    詳解SpringBoot啟動類的掃描注解的用法及沖突原則

    這篇文章主要介紹了詳解SpringBoot啟動類的掃描注解的用法及沖突原則,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Restful之通用返回格式類設(shè)計

    Restful之通用返回格式類設(shè)計

    這篇文章主要介紹了Restful之通用返回格式類設(shè)計,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Spring中集成Groovy的四種方式(小結(jié))

    Spring中集成Groovy的四種方式(小結(jié))

    這篇文章主要介紹了Spring中集成Groovy的四種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java之HashMap案例詳解

    Java之HashMap案例詳解

    這篇文章主要介紹了Java之HashMap案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Mybatis之mapper接口多參數(shù)方式

    Mybatis之mapper接口多參數(shù)方式

    這篇文章主要介紹了Mybatis之mapper接口多參數(shù)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • mybatis基本實例詳解

    mybatis基本實例詳解

    這篇文章主要介紹了mybatis基本實例詳解以及mybatis自由模糊查詢,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • spring?boot配置dubbo方式(properties)

    spring?boot配置dubbo方式(properties)

    這篇文章主要介紹了spring?boot配置dubbo方式(properties),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • SpringBoot整合Swagger教程詳解

    SpringBoot整合Swagger教程詳解

    SpringBoot是一個基于Spring框架的輕量級開源框架,它的出現(xiàn)極大地簡化了Spring應(yīng)用的搭建和開發(fā),本文將介紹如何在SpringBoot中使用Swagger來實現(xiàn)接口文檔的自動生成,感興趣的同學(xué)可以參考一下
    2023-04-04
  • springboot對接支付寶支付接口(詳細(xì)開發(fā)步驟總結(jié))

    springboot對接支付寶支付接口(詳細(xì)開發(fā)步驟總結(jié))

    這篇文章主要介紹了springboot對接支付寶支付接口(詳細(xì)開發(fā)步驟總結(jié)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Springboot集成第三方j(luò)ar快速實現(xiàn)微信、支付寶等支付場景

    Springboot集成第三方j(luò)ar快速實現(xiàn)微信、支付寶等支付場景

    這篇文章主要介紹了Springboot集成第三方j(luò)ar快速實現(xiàn)微信、支付寶等支付場景,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評論