日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

我們一起聊聊Java線程和CPU調(diào)度

來(lái)源: 責(zé)編: 時(shí)間:2023-10-31 10:25:17 266觀看
導(dǎo)讀什么是線程現(xiàn)代操作系統(tǒng)在運(yùn)行一個(gè)程序時(shí),會(huì)為其創(chuàng)建一個(gè)進(jìn)程,例如,我們啟動(dòng)一個(gè) Java 程序,系統(tǒng)就會(huì)創(chuàng)建一個(gè) Java 進(jìn)程,在一個(gè)進(jìn)程里可以創(chuàng)建多個(gè)線程,這些線程擁有自己的計(jì)數(shù)器、堆棧和局部變量等屬性,引入線程的概念可以

什么是線程

現(xiàn)代操作系統(tǒng)在運(yùn)行一個(gè)程序時(shí),會(huì)為其創(chuàng)建一個(gè)進(jìn)程,例如,我們啟動(dòng)一個(gè) Java 程序,系統(tǒng)就會(huì)創(chuàng)建一個(gè) Java 進(jìn)程,在一個(gè)進(jìn)程里可以創(chuàng)建多個(gè)線程,這些線程擁有自己的計(jì)數(shù)器、堆棧和局部變量等屬性,引入線程的概念可以將一個(gè)進(jìn)程的資源分配和執(zhí)行調(diào)度分開(kāi),并且能夠訪問(wèn)共享的內(nèi)存變量,如內(nèi)存地址和文件 I/O 等,線程是計(jì)算機(jī)中比進(jìn)程更輕量級(jí)的調(diào)度執(zhí)行單元,也是系統(tǒng)調(diào)度的最小單元,也叫輕量級(jí)進(jìn)程(Light Weight Process, LWP),CPU 在這些線程上高速切換,讓使用者感覺(jué)到這些線程在同時(shí)執(zhí)行。8I328資訊網(wǎng)——每日最新資訊28at.com

一個(gè) Java 程序從 main() 方法開(kāi)始執(zhí)行,然后按照既定的代碼邏輯執(zhí)行,看似沒(méi)有其他線程參與,但實(shí)際上 Java 程序天生就是多線程程序,因?yàn)閳?zhí)行 main() 方法的是一個(gè)名稱為 main 的線程。我們通過(guò)一段代碼看下一個(gè)普通的 Java 程序包含哪些線程。8I328資訊網(wǎng)——每日最新資訊28at.com

public class thread {  public static void main(String[] args) {    // 獲取Java線程管理    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();    // 僅獲取線程和線程堆棧信息    ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);    // 遍歷線程信息,僅僅打印線程 ID 和線程名稱信息    for (ThreadInfo threadInfo : threadInfos) {      System.out.println("[" + threadInfo.getThreadId() + "]" + threadInfo.getThreadName());    }  }}

圖片圖片8I328資訊網(wǎng)——每日最新資訊28at.com

可以看到,一個(gè) Java 程序的運(yùn)行不僅僅是 main() 方法的運(yùn)行,而是 main 線程和多個(gè)其他線程的同時(shí)運(yùn)行。8I328資訊網(wǎng)——每日最新資訊28at.com

線程的實(shí)現(xiàn)

主流的操作系統(tǒng)都提供了線程實(shí)現(xiàn)。Java 語(yǔ)言則提供了在不同硬件和操作系統(tǒng)平臺(tái)下對(duì)線程操作統(tǒng)一處理的能力。在 Java 中,每個(gè)已經(jīng)執(zhí)行 start() 方法且尚未結(jié)束的 java.lang.Thread 類的實(shí)例代表一個(gè)線程。8I328資訊網(wǎng)——每日最新資訊28at.com

查看 JDK 的 Thread 類可以看到 Thread 類與大部分 Java API 有明顯的差異,它的關(guān)鍵方法都被聲明為 Native。在 Java API 中,Native 方法通常意味著該方法沒(méi)有使用或無(wú)法使用平臺(tái)無(wú)關(guān)的手段來(lái)實(shí)現(xiàn)(說(shuō)明需要操作的是很底層的東西了,已經(jīng)脫離了 Java 語(yǔ)言層面的范疇)。8I328資訊網(wǎng)——每日最新資訊28at.com

圖片圖片8I328資訊網(wǎng)——每日最新資訊28at.com

實(shí)現(xiàn)線程主要有 3 種方式:使用內(nèi)核線程實(shí)現(xiàn)( 1:1 實(shí)現(xiàn))、使用用戶線程實(shí)現(xiàn)( N:1 實(shí)現(xiàn))和使用用戶線程加輕量級(jí)進(jìn)程混合實(shí)現(xiàn)( N:M 實(shí)現(xiàn))。8I328資訊網(wǎng)——每日最新資訊28at.com

1、內(nèi)核線程實(shí)現(xiàn)(1:1實(shí)現(xiàn))

內(nèi)核線程(Kernel-Level Thread, KLT)是由操作系統(tǒng)內(nèi)核直接支持的線程,內(nèi)核通過(guò)操縱調(diào)度器(Scheduler)對(duì)線程進(jìn)行調(diào)度,并負(fù)責(zé)將線程的任務(wù)映射到各個(gè)處理器上。下圖中 KLT 線程上面都有一個(gè) LWP 與之對(duì)應(yīng),每個(gè)內(nèi)核線程可以視為內(nèi)核的一個(gè)分身,這樣操作系統(tǒng)就能夠同時(shí)處理多個(gè)任務(wù),從而支持多線程。8I328資訊網(wǎng)——每日最新資訊28at.com

程序一般不會(huì)直接使用內(nèi)核線程,而是使用內(nèi)核線程的一種高級(jí)接口——輕量級(jí)進(jìn)程(Light Weight Process, LWP)。輕量級(jí)進(jìn)程是我們通常所說(shuō)的線程,由于每個(gè)輕量級(jí)進(jìn)程都由一個(gè)內(nèi)核線程支持,因此只有先支持內(nèi)核線程,才能有輕量級(jí)進(jìn)程。輕量級(jí)進(jìn)程與內(nèi)核線程之間是一對(duì)一的關(guān)系,稱為一對(duì)一的線程模型。8I328資訊網(wǎng)——每日最新資訊28at.com

由于內(nèi)核線程的支持,每個(gè)輕量級(jí)進(jìn)程都成為一個(gè)獨(dú)立的調(diào)度單元,即使有一個(gè)輕量級(jí)進(jìn)程在系統(tǒng)調(diào)用中阻塞了,也不會(huì)影響整個(gè)進(jìn)程繼續(xù)工作。但輕量級(jí)進(jìn)程也有一些局限性:由于是基于內(nèi)核線程實(shí)現(xiàn)的,各種線程操作,如創(chuàng)建、析構(gòu)及同步,都需要進(jìn)行系統(tǒng)調(diào)用。而系統(tǒng)調(diào)用的代價(jià)相對(duì)較高,需要在用戶態(tài)(User Mode)和內(nèi)核態(tài)(Kernel Mode)之間來(lái)回切換。其次,每個(gè)輕量級(jí)進(jìn)程都需要有一個(gè)內(nèi)核線程的支持,因此輕量級(jí)進(jìn)程要消耗一定的內(nèi)核資源(例如內(nèi)核線程的棧空間),因此一個(gè)系統(tǒng)支持輕量級(jí)進(jìn)程的數(shù)量是有限的。8I328資訊網(wǎng)——每日最新資訊28at.com

圖片圖片8I328資訊網(wǎng)——每日最新資訊28at.com

輕量級(jí)進(jìn)程與內(nèi)核線程之間1:1的示意圖8I328資訊網(wǎng)——每日最新資訊28at.com

2、用戶線程實(shí)現(xiàn)( N:1 實(shí)現(xiàn))

用戶線程是指完全建立在用戶空間線程庫(kù)之上的線程實(shí)現(xiàn),系統(tǒng)內(nèi)核對(duì)其不可感知。即所有的用戶線程都會(huì)對(duì)應(yīng)到一個(gè)內(nèi)核線程中,用戶線程的創(chuàng)建、同步、銷毀和調(diào)度完全在用戶空間中完成,無(wú)需內(nèi)核的幫助。如果程序?qū)崿F(xiàn)得當(dāng),這些線程無(wú)需切換到內(nèi)核模式,從而實(shí)現(xiàn)快速且低開(kāi)銷的操作。它們還可以支持更多的線程數(shù)量,因此在高性能數(shù)據(jù)庫(kù)等場(chǎng)景中經(jīng)常使用用戶線程。進(jìn)程與用戶線程之間的關(guān)系采用一對(duì)多的線程模型。8I328資訊網(wǎng)——每日最新資訊28at.com

使用用戶線程的優(yōu)勢(shì)在于不需要系統(tǒng)內(nèi)核的支持。然而劣勢(shì)在于它們也缺乏系統(tǒng)內(nèi)核的支持,所有線程操作都需要用戶程序自己處理。需要考慮線程創(chuàng)建、切換和調(diào)度等問(wèn)題。在某一線程被阻塞時(shí),會(huì)導(dǎo)致整個(gè)所屬進(jìn)程阻塞。Java 曾經(jīng)使用過(guò)用戶線程,但最終放棄了使用它們。但是比如 Golang、Erlang 等一些新的、以高并發(fā)為賣點(diǎn)的變成語(yǔ)言普遍支持了用戶線程。8I328資訊網(wǎng)——每日最新資訊28at.com

進(jìn)程與用戶線程之間N:1的關(guān)系示意圖進(jìn)程與用戶線程之間N:1的關(guān)系示意圖8I328資訊網(wǎng)——每日最新資訊28at.com

3、用戶線程加輕量級(jí)進(jìn)程混合實(shí)現(xiàn)( N:M 實(shí)現(xiàn))

內(nèi)核線程和用戶線程結(jié)合的實(shí)現(xiàn)方式。在這種混合實(shí)現(xiàn)中,用戶線程和輕量級(jí)進(jìn)程同時(shí)存在。用戶線程仍然完全建立在用戶空間中,因此創(chuàng)建、切換和銷毀用戶線程的操作仍然是廉價(jià)的,并且可以同時(shí)支持大量的用戶線程。操作系統(tǒng)提供對(duì)輕量級(jí)進(jìn)程的支持,它們充當(dāng)用戶線程和內(nèi)核線程之間的橋梁。這樣可以利用內(nèi)核提供的線程調(diào)度和處理器映射功能。用戶線程的系統(tǒng)調(diào)用通過(guò)輕量級(jí)進(jìn)程來(lái)處理,大大降低了整個(gè)進(jìn)程被完全阻塞的風(fēng)險(xiǎn)。在這種混合模型中,用戶線程和輕量級(jí)進(jìn)程的比例可以變化,形成一個(gè) N:M 的關(guān)系。8I328資訊網(wǎng)——每日最新資訊28at.com

許多 UNIX 系列的操作系統(tǒng)都提供了 N:M 的線程模型實(shí)現(xiàn)。這些操作系統(tǒng)上的應(yīng)用也相對(duì)更容易應(yīng)用 N:M 的線程模型。8I328資訊網(wǎng)——每日最新資訊28at.com

用戶線程與輕量級(jí)進(jìn)程之間N:M的關(guān)系示意圖用戶線程與輕量級(jí)進(jìn)程之間N:M的關(guān)系示意圖8I328資訊網(wǎng)——每日最新資訊28at.com

Java 線程的實(shí)現(xiàn)

操作系統(tǒng)支持怎么樣的線程模型,很大程度上會(huì)影響上面的 Java 虛擬機(jī)的線程是怎么映射的,JVM 規(guī)范里面沒(méi)有規(guī)定,必須使用哪一種模型。線程模型主要影響線程的并發(fā)規(guī)模和操作成本,對(duì)于 Java 程序的編碼和運(yùn)行過(guò)程來(lái)說(shuō),這些差異都是透明的, Java 作為上層應(yīng)用,其實(shí)是感知不到上面三種模型之間的區(qū)別的,即開(kāi)發(fā)者無(wú)需關(guān)注具體的線程模型細(xì)節(jié)。8I328資訊網(wǎng)——每日最新資訊28at.com

在 JDK 1.2 之前,Java 線程使用的是稱為“綠色線程”(Green Threads)的用戶級(jí)線程實(shí)現(xiàn)。但是在 JDK 1.3 起,線程模型被替換為基于操作系統(tǒng)原生線程模型的實(shí)現(xiàn)方式,即采用 1:1 的線程模型。8I328資訊網(wǎng)——每日最新資訊28at.com

Java SE 最常用的 JVM 是 Oracle/Sun 研發(fā)的 HotSpot VM。在這個(gè) JVM 的較新版本所支持的所有平臺(tái)上,它都是使用 1:1 線程模型的——除了 Solaris 之外,它是個(gè)特例。也就是說(shuō)一個(gè) Java 線程是直接通過(guò)一個(gè)操作系統(tǒng)原生線程來(lái)實(shí)現(xiàn)的,中間并沒(méi)有額外的間接結(jié)構(gòu)。而且 HotSpot VM 自己也不干涉線程的調(diào)度,全權(quán)交給底下的 OS 去處理。8I328資訊網(wǎng)——每日最新資訊28at.com

Java 線程調(diào)度

線程調(diào)度是指系統(tǒng)為線程分配處理器使用權(quán)的過(guò)程,主要調(diào)度方式有兩種,分別是協(xié)同式線程調(diào)度(Cooperative Threads-Scheduling)和搶占式線程調(diào)度(Preemptive Threads-Scheduling)。8I328資訊網(wǎng)——每日最新資訊28at.com

如果在多線程系統(tǒng)中使用協(xié)同式調(diào)度,每個(gè)線程的執(zhí)行時(shí)間由線程自身控制。在完成工作后,線程需要主動(dòng)通知系統(tǒng)切換到另一個(gè)線程。協(xié)同式多線程的主要優(yōu)勢(shì)在于簡(jiǎn)單性,由于線程切換由線程自身知曉,因此不存在線程同步問(wèn)題。協(xié)同式調(diào)度也存在明顯的缺點(diǎn)。線程的執(zhí)行時(shí)間無(wú)法控制,如果一個(gè)線程出現(xiàn)問(wèn)題并且沒(méi)有通知系統(tǒng)切換線程,整個(gè)進(jìn)程可能會(huì)無(wú)限期地被阻塞。8I328資訊網(wǎng)——每日最新資訊28at.com

如果一個(gè)多線程系統(tǒng)采用搶占式調(diào)度,系統(tǒng)會(huì)為每個(gè)線程分配執(zhí)行時(shí)間,線程切換不由線程自身決定(在 Java 中,Thread.yield() 可以讓出執(zhí)行時(shí)間,但線程本身無(wú)法控制獲取執(zhí)行時(shí)間)。在這種線程調(diào)度實(shí)現(xiàn)中,線程的執(zhí)行時(shí)間由系統(tǒng)控制,不會(huì)出現(xiàn)一個(gè)線程阻塞整個(gè)進(jìn)程的情況。Java 使用搶占式調(diào)度作為其線程調(diào)度機(jī)制。如果一個(gè)進(jìn)程遇到問(wèn)題,我們可以使用“任務(wù)管理器”終止該進(jìn)程,而不會(huì)導(dǎo)致系統(tǒng)崩潰。8I328資訊網(wǎng)——每日最新資訊28at.com

說(shuō)到計(jì)算調(diào)度這里還要說(shuō)一下 CPU 時(shí)間片8I328資訊網(wǎng)——每日最新資訊28at.com

在單個(gè)處理器的時(shí)期,操作系統(tǒng)就能處理多線程并發(fā)任務(wù)。處理器給每個(gè)線程分配 CPU 時(shí)間片(Time Slice),線程在分配獲得的時(shí)間片內(nèi)執(zhí)行任務(wù)。CPU 時(shí)間片是 CPU 分配給每個(gè)線程執(zhí)行的時(shí)間段,一般為幾十毫秒。在這么短的時(shí)間內(nèi)線程互相切換,我們根本感覺(jué)不到,所以看上去就好像是同時(shí)進(jìn)行的一樣。8I328資訊網(wǎng)——每日最新資訊28at.com

時(shí)間片決定了一個(gè)線程可以連續(xù)占用處理器運(yùn)行的時(shí)長(zhǎng)。當(dāng)一個(gè)線程的時(shí)間片用完了,或者因自身原因被迫暫停運(yùn)行了,這個(gè)時(shí)候,另外一個(gè)線程(可以是同一個(gè)線程或者其它進(jìn)程的線程)就會(huì)被操作系統(tǒng)選中,來(lái)占用處理器。這種一個(gè)線程被暫停剝奪使用權(quán),另外一個(gè)線程被選中開(kāi)始或者繼續(xù)運(yùn)行的過(guò)程就叫做上下文切換。8I328資訊網(wǎng)——每日最新資訊28at.com

上下文切換

當(dāng)一個(gè)線程讓出 CPU 時(shí)間片時(shí),它需要記錄下整個(gè)執(zhí)行上下文,以便在恢復(fù)執(zhí)行時(shí)從上次離開(kāi)的地方繼續(xù)。這包括變量、計(jì)算結(jié)果、程序計(jì)數(shù)器等等。就像是對(duì)線程的運(yùn)行環(huán)境進(jìn)行快照,這樣當(dāng)它重新獲得 CPU 時(shí)間時(shí),可以通過(guò)檢索保存的數(shù)據(jù)快速恢復(fù)先前的執(zhí)行上下文。這個(gè)過(guò)程被稱為“上下文切換”。8I328資訊網(wǎng)——每日最新資訊28at.com

在一個(gè)擁有多個(gè) CPU 的系統(tǒng)中,操作系統(tǒng)以循環(huán)方式將 CPU 分配給不同的線程。這導(dǎo)致上下文切換更加頻繁,特別是在跨不同 CPU 進(jìn)行上下文切換時(shí),比單個(gè) CPU 內(nèi)的上下文切換更加昂貴。8I328資訊網(wǎng)——每日最新資訊28at.com

在操作系統(tǒng)中,上下文切換可以發(fā)生在進(jìn)程之間或線程之間。在多線程編程的背景下,我們主要關(guān)注線程之間上下文切換的性能影響。現(xiàn)在,讓我們探討一下多線程中上下文切換的原因。但在此之前,讓我們先了解一下系統(tǒng)線程的生命周期狀態(tài)。8I328資訊網(wǎng)——每日最新資訊28at.com

圖片圖片8I328資訊網(wǎng)——每日最新資訊28at.com

系統(tǒng)線程主要有“新建”(NEW)、“就緒”(RUNNABLE)、“運(yùn)行”(RUNNING)、“阻塞”(BLOCKED)、“死亡”(DEAD)五種狀態(tài)。到了 Java 層面它們都被映射為了 NEW、RUNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINADTED 等 6 種狀態(tài)。8I328資訊網(wǎng)——每日最新資訊28at.com

在這個(gè)運(yùn)行過(guò)程中,線程由 RUNNABLE 轉(zhuǎn)為非 RUNNABLE 的過(guò)程就是線程上下文切換。一個(gè)線程的狀態(tài)由 RUNNING 轉(zhuǎn)為 BLOCKED ,再由 BLOCKED 轉(zhuǎn)為 RUNNABLE ,然后再被調(diào)度器選中執(zhí)行,這就是一個(gè)上下文切換的過(guò)程。多線程的上下文切換實(shí)際上就是由多線程兩個(gè)運(yùn)行狀態(tài)的互相切換導(dǎo)致的。8I328資訊網(wǎng)——每日最新資訊28at.com

那么在線程運(yùn)行時(shí),線程狀態(tài)由 RUNNING 轉(zhuǎn)為 BLOCKED 或者由 BLOCKED 轉(zhuǎn)為 RUNNABLE,是怎么誘發(fā)的呢?8I328資訊網(wǎng)——每日最新資訊28at.com

系統(tǒng)線程切換可以由多種情況下誘發(fā),包括但不限于以下幾種情況:8I328資訊網(wǎng)——每日最新資訊28at.com

  1. 時(shí)間片耗盡:當(dāng)一個(gè)線程的時(shí)間片用盡時(shí),操作系統(tǒng)會(huì)強(qiáng)制切換到另一個(gè)線程,以確保公平地分配 CPU 時(shí)間給其他線程。
  2. 高優(yōu)先級(jí)線程搶占:如果有一個(gè)優(yōu)先級(jí)更高的線程需要執(zhí)行,操作系統(tǒng)會(huì)中斷當(dāng)前線程的執(zhí)行,并切換到優(yōu)先級(jí)更高的線程。
  3. 阻塞操作:當(dāng)一個(gè)線程執(zhí)行阻塞操作(如等待 I/O 完成、等待鎖釋放等)時(shí),操作系統(tǒng)會(huì)將該線程置于阻塞狀態(tài),并切換到其他可執(zhí)行的線程,以充分利用 CPU 資源。
  4. 線程同步:當(dāng)多個(gè)線程需要訪問(wèn)共享資源時(shí),可能需要進(jìn)行線程同步操作,如互斥鎖、信號(hào)量等。在這種情況下,當(dāng)一個(gè)線程獲取到同步資源時(shí),其他線程可能需要等待,從而引發(fā)線程切換。
  5. 中斷處理:當(dāng)一個(gè)硬件中斷或軟件中斷發(fā)生時(shí),操作系統(tǒng)會(huì)中斷當(dāng)前線程的執(zhí)行,并轉(zhuǎn)而處理中斷事件,這可能導(dǎo)致線程切換。這些情況下,操作系統(tǒng)會(huì)根據(jù)調(diào)度算法和優(yōu)先級(jí)規(guī)則來(lái)決定切換到哪個(gè)線程,并通過(guò)保存和恢復(fù)線程的上下文來(lái)實(shí)現(xiàn)線程切換。

我們可以分兩種情況來(lái)分析,一種是程序本身觸發(fā)的切換,這種我們稱為自發(fā)性上下文切換,另一種是由系統(tǒng)或者虛擬機(jī)誘發(fā)的非自發(fā)性上下文切換。8I328資訊網(wǎng)——每日最新資訊28at.com

接下來(lái)我們看一段代碼,來(lái)對(duì)比串聯(lián)執(zhí)行和并發(fā)執(zhí)行的速度8I328資訊網(wǎng)——每日最新資訊28at.com

package com.yuyy.test;public class DemoApplication {  public static void main(String[] args) {    // 運(yùn)行多線程    MultiThreadTester test1 = new MultiThreadTester();    test1.Start();    // 運(yùn)行單線程    SerialTester test2 = new SerialTester();    test2.Start();  }                static class MultiThreadTester extends ThreadContextSwitchTester {    @Override    public void Start() {      long start = System.currentTimeMillis();      MyRunnable myRunnable1 = new MyRunnable();      Thread[] threads = new Thread[4];      // 創(chuàng)建多個(gè)線程      for (int i = 0; i < 4; i++) {        threads[i] = new Thread(myRunnable1);        threads[i].start();      }      for (int i = 0; i < 4; i++) {        try {          // 等待一起運(yùn)行完          threads[i].join();        } catch (InterruptedException e) {          e.printStackTrace();        }      }      long end = System.currentTimeMillis();      System.out.println("multi thread exec time: " + (end - start) + "s");      System.out.println("counter: " + counter);    }    // 創(chuàng)建一個(gè)實(shí)現(xiàn)Runnable的類    class MyRunnable implements Runnable {      public void run() {        while (counter < 100000000) {          synchronized (this) {            if(counter < 100000000) {              increaseCounter();            }          }        }      }     }   }          // 創(chuàng)建一個(gè)單線程   static class SerialTester extends ThreadContextSwitchTester{     @Override     public void Start() {       long start = System.currentTimeMillis();       for (long i = 0; i < count; i++) {         increaseCounter();       }       long end = System.currentTimeMillis();       System.out.println("serial exec time: " + (end - start) + "s");       System.out.println("counter: " + counter);     }   }   static abstract class ThreadContextSwitchTester {     public static final int count = 100000000;     public volatile int counter = 0;     public void increaseCounter() {                this.counter += 1;     }     public abstract void Start();   }}

執(zhí)行之后,看一下兩者的時(shí)間測(cè)試結(jié)果:串聯(lián)的執(zhí)行速度比并發(fā)的執(zhí)行速度要快。這就是因?yàn)榫€程的上下文切換導(dǎo)致了額外的開(kāi)銷。8I328資訊網(wǎng)——每日最新資訊28at.com

圖片圖片8I328資訊網(wǎng)——每日最新資訊28at.com

線程的優(yōu)先級(jí)

雖然 Java 線程調(diào)度由系統(tǒng)自動(dòng)處理,但我們?nèi)匀豢梢浴敖ㄗh”系統(tǒng)為某些線程分配更多的執(zhí)行時(shí)間,而為其他線程分配較少的執(zhí)行時(shí)間。這可以通過(guò)設(shè)置線程優(yōu)先級(jí)來(lái)實(shí)現(xiàn)。Java 語(yǔ)言提供了 10 個(gè)級(jí)別的線程優(yōu)先級(jí)。當(dāng)兩個(gè)線程同時(shí)處于 Ready 狀態(tài)時(shí),優(yōu)先級(jí)較高的線程更有可能被系統(tǒng)選擇執(zhí)行,其實(shí)就是讓高優(yōu)先級(jí)的線程獲得更多的CPU 時(shí)間片。8I328資訊網(wǎng)——每日最新資訊28at.com

設(shè)置優(yōu)先級(jí)有助于”線程規(guī)劃期“確定在下一次選擇哪一個(gè)線程來(lái)優(yōu)先執(zhí)行,設(shè)置線程優(yōu)先級(jí)使用 setPriority() 方法8I328資訊網(wǎng)——每日最新資訊28at.com

圖片圖片8I328資訊網(wǎng)——每日最新資訊28at.com

但是,線程優(yōu)先級(jí)并不總是可靠的,因?yàn)?Java 線程最終是通過(guò)映射到底層操作系統(tǒng)的原生線程來(lái)實(shí)現(xiàn)的。因此,線程調(diào)度仍然取決于操作系統(tǒng)。盡管許多操作系統(tǒng)提供了線程優(yōu)先級(jí)的概念,但它們不一定直接對(duì)應(yīng)于 Java 線程優(yōu)先級(jí)。例如,Solaris 擁有 2,147,483,648(2^32)個(gè)優(yōu)先級(jí)級(jí)別,而 Windows 只有 7 個(gè)。如果操作系統(tǒng)的優(yōu)先級(jí)級(jí)別多于 Java,將它們映射是相對(duì)簡(jiǎn)單的,可以在它們之間留下一些空位。然而,如果操作系統(tǒng)的優(yōu)先級(jí)級(jí)別少于 Java,可能會(huì)出現(xiàn)多個(gè)優(yōu)先級(jí)映射到同一級(jí)別的情況。8I328資訊網(wǎng)——每日最新資訊28at.com

下圖顯示了 Java 線程優(yōu)先級(jí)與 Windows 線程優(yōu)先級(jí)之間的對(duì)應(yīng)關(guān)系,不包括 THREAD_PRIORITY_IDLE,因?yàn)樗?Windows 平臺(tái)的 JDK 中未使用。因此如果在 Java 程序中對(duì)兩個(gè)線程設(shè)置的優(yōu)先級(jí)分別是 3 和 4 那么對(duì)于Windows 來(lái)說(shuō)他們的優(yōu)先級(jí)還是一致的。還有例如 Windows 系統(tǒng)中存在一個(gè)叫做“優(yōu)先級(jí)推進(jìn)器”的功能,大致作用是當(dāng)系統(tǒng)發(fā)現(xiàn)一個(gè)線程被執(zhí)行的特別頻繁的時(shí)候,可能會(huì)越過(guò)線程優(yōu)先級(jí)去為它分配執(zhí)行時(shí)間,從而減少線程頻繁切換而帶來(lái)的性能損耗。因此我們?cè)诔绦蛑胁⒉荒芘袛嗤瑯訛榫途w狀態(tài)且優(yōu)先級(jí)一致的多個(gè)線程系統(tǒng)會(huì)先執(zhí)行哪一個(gè)。8I328資訊網(wǎng)——每日最新資訊28at.com

圖片圖片8I328資訊網(wǎng)——每日最新資訊28at.com

總結(jié)

對(duì)于任何支持多線程的計(jì)算機(jī)語(yǔ)言來(lái)說(shuō),深入理解線程及寫好多線程程序,都是一個(gè)巨大的挑戰(zhàn)。本主要簡(jiǎn)述 Java 線程與操作系統(tǒng)線程之間的關(guān)系。java 中的線程和操作系統(tǒng)中的線程分別存在于虛擬機(jī)和操作系統(tǒng)中,一個(gè) Java 線程是直接通過(guò)一個(gè)操作系統(tǒng)線程來(lái)實(shí)現(xiàn)的。其中還有很多值得深挖的點(diǎn)。大家有興趣的話,可以仔細(xì)研究一下。8I328資訊網(wǎng)——每日最新資訊28at.com

參考文檔

深入理解Java虛擬機(jī)(第3版)8I328資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-16010-0.html我們一起聊聊Java線程和CPU調(diào)度

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Python控制流程:條件、循環(huán)和異常處理

下一篇: C++讀取文件和寫入文件內(nèi)容實(shí)例詳解

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 盘锦市| 永清县| 砚山县| 惠水县| 肃宁县| 米泉市| 古浪县| 上犹县| 泰兴市| 黄陵县| 威海市| 和平区| 施秉县| 勃利县| 涟源市| 静海县| 胶州市| 永胜县| 昭通市| 盖州市| 财经| 寿光市| 长春市| 光山县| 沐川县| 竹山县| 信阳市| 上栗县| 明光市| 嘉定区| 洪雅县| 广州市| 霸州市| 南部县| 高碑店市| 渭源县| 祁门县| 马关县| 博湖县| 南漳县| 蓝山县|