基本模型
由于Java 中,JVM主要是由C/C++實現(xiàn),所以Java層線程最終還是會映射到JVM層線程,而Java層的線程到操作系統(tǒng)層線程就得需要看具體的JVM的具體實現(xiàn)來決定。
一般來說,我們都把用戶線程看作更高層面的線程,而內(nèi)核線程則向用戶線程提供支持。
由此可見,用戶線程和內(nèi)核線程之間必然存在一定的映射關(guān)系,不同的操作系統(tǒng)可能采取不同的映射方式。
一般來說,按照映射方式來看,主要可以分為:多對一映射(用戶級方式),一對一映射(內(nèi)核級方式) 和多對多映射(組合方式)3種方式。其中:
1. 多對一映射(用戶級方式)
多對一映射是指多個用戶線程被映射到一個內(nèi)核線程上。每一個進程都對應(yīng)著一個內(nèi)核線程,進程內(nèi)的所有線程也都對應(yīng)著該內(nèi)核線程。
多對一映射模型是指多條用戶線程映射同一條內(nèi)核線程的情況,其中用戶線程由庫調(diào)度器進行調(diào)度,而內(nèi)核線程由操作系統(tǒng)調(diào)度器來完成。
對于用戶線程而言,其會按照一定的策略輪流執(zhí)行,具體的調(diào)度算法有庫調(diào)度器完成。
任意一個時刻每一個進程中都只有一個用戶線程被執(zhí)行,它們的執(zhí)行都由用戶態(tài)的代碼完成切換。
在不支持線程的操作系統(tǒng)中有庫來實現(xiàn)線程控制,用戶線程創(chuàng)建,銷毀,切換的開銷代價比內(nèi)核線程小。
因此,這種模式特點主要有兩點:
首先,可以節(jié)省內(nèi)核態(tài)到用戶態(tài)切換的開銷
其次,線程的數(shù)量不會受到內(nèi)核線程的限制
但是,因為線程切換的工作是由用戶態(tài)的代碼完成的,所以一個進程內(nèi),如果當一條線程發(fā)生阻塞時,與該內(nèi)核線程對應(yīng)的進程內(nèi)的其他所有的用戶線程也會一起陷入阻塞。
2. 一對一映射(內(nèi)核級方式)
一對一映射是指每個用戶線程都會被影射到一個內(nèi)核線程上,用戶的整個生命周期都綁定到所映射的內(nèi)核線程上。一個進程內(nèi)可以有一個用戶線程和至少一個用戶線程,都對應(yīng)著各自一個和至少一個內(nèi)核線程,進程內(nèi)的所有線程也都一一對應(yīng)著各自內(nèi)核線程。
一對一映射模型是指一條用戶線程對應(yīng)著內(nèi)核中的一條線程的情況,其中用戶線程由庫調(diào)度器進行調(diào)度,而內(nèi)核線程由操作系統(tǒng)調(diào)度器來完成,而Java中采用的就是這種模型。
在這種方式下,多個CPU能并行執(zhí)行同一個進程內(nèi)的多個線程。
如果進程內(nèi)的某個線程被阻塞,就可以切換到該進程的其他線程繼續(xù)執(zhí)行,并且能切換執(zhí)行其他進程的線程。
一對一映射模型是真正意義上的并行執(zhí)行,因為這種模型下,創(chuàng)建一條Java的Thread線程是真正的在內(nèi)核中創(chuàng)建并映射了一條內(nèi)核線程的,執(zhí)行過程中,一條線程不會因為另外一條線程的原因而發(fā)生阻塞等情況。
不過因為是每一個用線程都需要對應(yīng)一個內(nèi)核線程,這種直接映射內(nèi)核線程的模式,所以數(shù)量會存在上限。
并且同一個核心中,多條線程的執(zhí)行需要頻繁的發(fā)生上下文切換以及內(nèi)核態(tài)與用戶態(tài)之間的切換,所以如果線程數(shù)量過多,切換過于頻繁會導致線程執(zhí)行效率下降。
3. 多對多映射(組合方式)
多對多映射是指將一對一映射(內(nèi)核級方式)和多對一映射(用戶級方式)組合起來,通過綜合兩者優(yōu)點來形成的一種映射方式。該方式在用戶空間創(chuàng)建,銷毀,切換,調(diào)度線程,但是進程中的多個用戶線程會被影射到若干個內(nèi)核線程上。
多對多映射模型就可以避免上面一對一映射模型和多對一映射模型帶來的弊端,也就是多條用戶線程映射多條內(nèi)核線程,這樣即可以避免一對一映射模型的切換效率問題和數(shù)量限制問題,也可以避免多對一映射模型的阻塞問題。
每一個內(nèi)核線程負責與之綁定的若干用戶線程,進程中的某個線程發(fā)生系統(tǒng)阻塞并不會導致整個進程阻塞,而阻塞該內(nèi)核線程內(nèi)的所對應(yīng)的若干用戶線程,其他線程依舊可以照常執(zhí)行。
同時,因為用戶線程數(shù)量比內(nèi)核線程數(shù)量多,所以能有效減少內(nèi)核線程開銷。