色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

為什么Java線程沒有Running狀態?

Android編程精選 ? 來源:開源博客 ? 作者:國棟 ? 2021-06-17 17:36 ? 次閱讀

什么是 RUNNABLE?

與傳統的ready狀態的區別

與傳統的running狀態的區別

當I/O阻塞時

如何看待RUNNABLE狀態?

Java虛擬機層面所暴露給我們的狀態,與操作系統底層的線程狀態是兩個不同層面的事。

具體而言,這里說的 Java 線程狀態均來自于 Thread 類下的 State 這一內部枚舉類中所定義的狀態:

什么是 RUNNABLE?

直接看它的 Javadoc 中的說明:

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

那么 runnable 與圖中的 ready 與 running 區別在哪呢?

與傳統的ready狀態的區別

更具體點,javadoc 中是這樣說的:

處于 runnable 狀態下的線程正在 Java 虛擬機中執行,但它可能正在等待來自于操作系統的其它資源,比如處理器

A thread in the runnable state is executing in the Java virtual machine but it may be waiting forother resources from the operating system such as processor.

顯然,runnable 狀態實質上是包括了 ready 狀態的。

甚至還可能有包括上圖中的 waiting 狀態的部分細分狀態,在后面我們將會看到這一點

與傳統的running狀態的區別

有人常覺得 Java 線程狀態中還少了個 running 狀態,這其實是把兩個不同層面的狀態混淆了。

對 Java 線程狀態而言,不存在所謂的running 狀態,它的 runnable 狀態包含了 running 狀態。

我們可能會問,為何 JVM 中沒有去區分這兩種狀態呢?

現在的時分(time-sharing)多任務(multi-task)操作系統架構通常都是用所謂的“時間分片(time quantum or time slice)”方式進行搶占式(preemptive)輪轉調度(round-robin式)。

更復雜的可能還會加入優先級(priority)的機制。

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

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

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

這一切換的過程稱為線程的上下文切換(context switch),當然 cpu 不是簡單地把線程踢開就完了,還需要把被相應的執行狀態保存到內存中以便后續的恢復執行。

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

不計切換開銷(每次在1ms 以內),相當于1秒內有50-100次切換。

事實上時間片經常沒用完,線程就因為各種原因被中斷,實際發生的切換次數還會更多。

也這正是單核 *CPU 上實現所謂的“并發*(concurrent)”的基本原理,但其實是快速切換所帶來的假象

這有點類似一個手腳非常快的雜耍演員可以讓好多個球同時在空中運轉那般。

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

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

通常,Java的線程狀態是服務于監控的,如果線程切換得是如此之快,那么區分 ready 與 running 就沒什么太大意義了。

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

當然,對于精確的性能評估而言,獲得準確的 running 時間是有必要的。

現今主流的 JVM 實現都把 Java 線程一一映射到操作系統底層的線程上,把調度委托給了操作系統,我們在虛擬機層面看到的狀態實質是對底層狀態的映射及包裝。

JVM 本身沒有做什么實質的調度,把底層的 ready 及 running 狀態映射上來也沒多大意義,因此,統一成為runnable 狀態是不錯的選擇。

我們將看到,Java 線程狀態的改變通常只與自身顯式引入的機制有關。

當I/O阻塞時

我們知道傳統的I/O都是阻塞式(blocked)的,原因是I/O操作比起cpu來實在是太慢了,可能差到好幾個數量級都說不定。

如果讓 cpu 去等I/O 的操作,很可能時間片都用完了,I/O 操作還沒完成呢,不管怎樣,它會導致 cpu 的利用率極低。

所以,解決辦法就是:一旦線程中執行到 I/O 有關的代碼,相應線程立馬被切走,然后調度 ready 隊列中另一個線程來運行。

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

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

當然了,我們所謂阻塞只是指這段時間 cpu 暫時不會理它了,但另一個部件比如硬盤則在努力地為它服務。

cpu 與硬盤間是并發的,如果把線程視作為一個 job,這一 job 由 cpu 與硬盤交替協作完成,當在 cpu 上是 waiting 時,在硬盤上卻處于 running,只是我們在操作系統層面討論線程狀態時通常是圍繞著 cpu 這一中心去述說的。

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

也即所謂的“中斷驅動(interrupt-driven)”,現代操作系統基本都采用這一機制。

某種意義上,這也是控制反轉(IoC)機制的一種體現,cpu不用反復去詢問硬盤,這也是所謂的“好萊塢原則”—Don’t call us, we will call you.好萊塢的經紀人經常對演員們說:“別打電話給我,(有戲時)我們會打電話給你。”

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

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

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

另一方面,所謂的時間分片輪轉本質上也是由一個定時器定時中斷來驅動的,可以使線程從 running 回到 ready 狀態:

比如設置一個10ms 的倒計時,時間一到就發一個中斷,好像大限已到一樣,然后重置倒計時,如此循環。

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

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

現在問題來了,進行阻塞式 I/O 操作時,Java 的線程狀態究竟是什么?是 BLOCKED?還是 WAITING?

可能你已經猜到,既然放到 RUNNABLE 這一主題下討論,其實狀態還是 RUNNABLE。我們也可以通過一些測試來驗證這一點:

@Test public void testInBlockedIOState() throws InterruptedException

{ Scanner in = new Scanner(System.in); // 創建一個名為“輸入輸出”的線程

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已經得到執行 Thread.sleep(100); // 狀態為RUNNABLE assertThat(t.getState()).isEqualTo(Thread.State.RUNNABLE); }

在最后的語句上加一斷點,監控上也反映了這一點:

網絡阻塞時同理,比如socket.accept,我們說這是一個“阻塞式(blocked)”式方法,但線程狀態還是 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已經得到執行 Thread.sleep(500); // 狀態為RUNNABLE assertThat(serverThread.getState()).isEqualTo(Thread.State.RUNNABLE); }:

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

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

如何看待RUNNABLE狀態?

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

虛擬機是騎在你操作系統上面的,身下的操作系統是作為某種資源為滿足虛擬機的需求而存在的:

當進行阻塞式的 IO 操作時,或許底層的操作系統線程確實處在阻塞狀態,但我們關心的是 JVM 的線程狀態。

JVM 并不關心底層的實現細節,什么時間分片也好,什么 IO 時就要切換也好,它并不關心。

前面說到,“處于 runnable 狀態下的線程正在* Java 虛擬機中執行,但它可能正在等待*來自于操作系統的其它資源,比如處理器。”

JVM 把那些都視作資源,cpu 也好,硬盤,網卡也罷,有東西在為線程服務,它就認為線程在“執行”。

處于 IO 阻塞,只是說 cpu 不執行線程了,但網卡可能還在監聽呀,雖然可能暫時沒有收到數據:

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

所以 JVM 認為線程還在執行。而操作系統的線程狀態是圍繞著 cpu 這一核心去述說的,這與 JVM 的側重點是有所不同的。

前面我們也強調了“Java 線程狀態的改變通常只與自身顯式引入的機制有關”,如果 JVM 中的線程狀態發生改變了,通常是自身機制引發的。

比如 synchronize 機制有可能讓線程進入BLOCKED 狀態,sleep,wait等方法則可能讓其進入 WATING 之類的狀態。

RUNNABLE 狀態對應了傳統的 ready, running 以及部分的 waiting 狀態。

原文標題:為什么 Java 線程沒有 Running 狀態?一下被問懵!

文章出處:【微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

責任編輯:haq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JAVA
    +關注

    關注

    19

    文章

    2972

    瀏覽量

    104861
  • 虛擬機
    +關注

    關注

    1

    文章

    919

    瀏覽量

    28279

原文標題:為什么 Java 線程沒有 Running 狀態?一下被問懵!

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Java 23功能介紹

    Java 23 包含全新和更新的 Java 語言功能、核心 API 以及 JVM,同時適合新的 Java 開發者和高級開發者。從?IntelliJ IDEA 2024.2?開始已支持 Java
    的頭像 發表于 12-04 10:02 ?261次閱讀
    <b class='flag-5'>Java</b> 23功能介紹

    socket 多線程編程實現方法

    在現代網絡編程中,多線程技術被廣泛應用于提高服務器的并發處理能力。Socket編程是網絡通信的基礎,而將多線程技術應用于Socket編程,可以顯著提升服務器的性能。 多線程編程的基本概念 多
    的頭像 發表于 11-12 14:16 ?398次閱讀

    買藥秒送 JADE動態線程池實踐及原理淺析

    ,我們通過3輪高保真壓測最終初步確定了線程池的核心參數。但我們仍面臨一些保障系統穩定性問題:如何監控線程池運行狀態?以及因流量飆升出現任務堆積和拒絕時能否實時報警,線程池核心參數能否做
    的頭像 發表于 09-04 11:11 ?864次閱讀
    買藥秒送 JADE動態<b class='flag-5'>線程</b>池實踐及原理淺析

    CPU線程和程序線程的區別

    CPU的線程與程序的線程在概念、作用、實現方式以及性能影響等方面存在顯著差異。以下是對兩者區別的詳細闡述,旨在深入探討這一技術話題。
    的頭像 發表于 09-02 11:18 ?1079次閱讀

    華納云:java web和java有什么區別java web和java有什么區別

    Java Web和Java是兩個不同的概念,它們在功能、用途和實現方式上存在一些區別,下面將詳細介紹它們之間的區別。 1. 功能和用途: – Java是一種編程語言,它提供了一種用于開發各種應用程序
    的頭像 發表于 07-16 13:35 ?834次閱讀
    華納云:<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么區別<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么區別

    從多線程設計模式到對 CompletableFuture 的應用

    最近在開發 延保服務 頻道頁時,為了提高查詢效率,使用到了多線程技術。為了對多線程方案設計有更加充分的了解,在業余時間讀完了《圖解 Java線程設計模式》這本書,覺得收獲良多。本篇
    的頭像 發表于 06-26 14:18 ?372次閱讀
    從多<b class='flag-5'>線程</b>設計模式到對 CompletableFuture 的應用

    探索虛擬線程:原理與實現

    虛擬線程的引入與優勢 在Loom項目之前,Java虛擬機(JVM)中的線程是通過java.lang.Thread類型來實現的,這些線程被稱為
    的頭像 發表于 06-24 11:35 ?321次閱讀
    探索虛擬<b class='flag-5'>線程</b>:原理與實現

    鴻蒙開發:【線程模型】

    管理其他線程的ArkTS引擎實例,例如使用TaskPool(任務池)創建任務或取消任務、啟動和終止Worker線程
    的頭像 發表于 06-13 16:38 ?427次閱讀
    鴻蒙開發:【<b class='flag-5'>線程</b>模型】

    動態線程池思想學習及實踐

    相關文檔 美團線程池實踐:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html 線程池思想解析:https
    的頭像 發表于 06-13 15:43 ?1204次閱讀
    動態<b class='flag-5'>線程</b>池思想學習及實踐

    在GPIF設計器中設計狀態機時,無法訪問附件中所示的線程編號如何解決?

    在 GPIF 設計器中設計狀態機時,我無法訪問附件中所示的線程編號、 如何解決這個問題?
    發表于 05-23 07:18

    java實現多線程的幾種方式

    Java實現多線程的幾種方式 多線程是指程序中包含了兩個或以上的線程,每個線程都可以并行執行不同的任務或操作。
    的頭像 發表于 03-14 16:55 ?741次閱讀

    什么是動態線程池?動態線程池的簡單實現思路

    因此,動態可監控線程池一種針對以上痛點開發的線程池管理工具。主要可實現功能有:提供對 Spring 應用內線程池實例的全局管控、應用運行時動態變更線程池參數以及
    的頭像 發表于 02-28 10:42 ?658次閱讀

    關于FX3使用4個線程進行FPGA到USB的數據傳輸-狀態機設置的問題求解

    我現在使用FX3來實現FPGA到上位機的數據傳輸,在使用2個線程用類似于UVC實例中的乒乓機制傳輸時沒有問題。我看到GPIF II最多支持4個線程,所以想試一下4個線程的數據傳輸,我使
    發表于 02-27 06:40

    RTT Nano線程創建成功,沒有進入線程創建的函數運行怎么解決?

    RTT Nano線程創建成功,沒有進入線程創建的函數運行int main(void) { interrupt_config(); // gd_eval_led_init(LED1
    發表于 02-26 06:27

    .NET8性能優化之線程

    目前來說,沒有確切的證據證明哪個線程池好用,或者效率更高。但是開發者可以使用上面的選項來進行自己的選擇,有一個測試就是在Windows線程池在比較大的機器上的IO擴展性不太好。如果你的應用程序已經
    的頭像 發表于 01-22 14:50 ?1181次閱讀
    主站蜘蛛池模板: 理论片在线观看片免费| 啪啪后入内射日韩| 小草观看免费高清视频| 国产亚洲tv在线观看| 亚洲精品视频观看| 久久99国产精品二区不卡| 最新黄色在线| 日本十八禁无遮拦啪啪漫画| 国产一区二区免费在线观看| 2021国产精品久久久久精品免费网| 妻子撸av中文字幕| 国产精品无码久久久久不卡| 樱桃视频高清免费观看在线播放| 欧美jizz19性欧美| 国产亚洲精品久久久久久禁果TV | 精品国产成人AV在线看| 99re在这里只有精品| 无人区乱码1区2区3区网站| 伦理片 a在线线版韩国| 国产精品麻豆高潮刺激A片| 37pao成人国产永久免费视频| 十七岁日本免费完整版BD| 老师那里好大又粗h男男| 国产精品亚洲精品日韩电影| 99视频免视看| 一级做a爰片久久免费| 色综合久久网女同蕾丝边| 美女一级毛片免费不卡视频| 国产人妻麻豆蜜桃色精| xxxxxl荷兰| 最近韩国日本免费观看mv免费版| 无遮挡午夜男女XX00动态| 欧美色图天堂网| 老女老肥熟国产在线视频| 国产伊人久久| 国产ZZJJZZJJ视频全免费| adc网址在线观看| 最新中文字幕在线视频| 亚洲免费在线| 午夜伦yy44880影院| 日本高清无卡码一区二区久久 |