Linux從核心2.6開始使用NPTL (Native POSIX Thread Library)支援,但這時執行緒本質上還輕量級程序。 

Java裡的執行緒是由JVM來管理的,它如何對應到作業系統的執行緒是由JVM的實現來確定的。Linux 2.6上的HotSpot使用了NPTL機制,JVM執行緒跟核心輕量級程序有一一對應的關係。執行緒的排程完全交給了作業系統核心,當然jvm還保留一些策略足以影響到其內部的執行緒排程,舉個例子,在linux下,只要一個Thread.run就會呼叫一個fork產生一個執行緒。

 

Java執行緒在Windows及Linux平臺上的實現方式,現在看來,是核心執行緒的實現方式。這種方式實現的執行緒,是直接由作業系統核心支援的——由核心完成執行緒切換,核心通過操縱排程器(Thread Scheduler)實現執行緒排程,並將執行緒任務反映到各個處理器上。核心執行緒是核心的一個分身。程式一般不直接使用該核心執行緒,而是使用其高階介面,即輕量級程序(LWP),也即執行緒。這看起來可能很拗口。看圖:

(說明:KLT即核心執行緒Kernel Thread,是“核心分身”。每一個KLT對應到程序P中的某一個輕量級程序LWP(也即執行緒),期間要經過使用者態、核心態的切換,並在Thread Scheduler 下反應到處理器CPU上。)

這種執行緒實現的方式也有它的缺陷:在程式面上使用核心執行緒,必然在作業系統上多次來回切換使用者態及核心態;另外,因為是一對一的執行緒模型,LWP的支援數是有限的。

對於一個大型程式,我們可以開闢的執行緒數量至少等於執行機器的cpu核心數量。java程式裡我們可以通過下面的一行程式碼得到這個數量:

Runtime.getRuntime().availableProcessors();

所以最小執行緒數量即時cpu核心數量。如果所有的任務都是計算密集型的,這個最小執行緒數量就是我們需要的執行緒數。開闢更多的執行緒只會影響程式的效能,因為執行緒之間的切換工作,會消耗額外的資源。如果任務是IO密集型的任務,我們可以開闢更多的執行緒執行任務。當一個任務執行IO操作的時候,執行緒將會被阻塞,處理器立刻會切換到另外一個合適的執行緒去執行。如果我們只擁有與核心數量一樣多的執行緒,即使我們有任務要執行,他們也不能執行,因為處理器沒有可以用來排程的執行緒。

        如果執行緒有50%的時間被阻塞,執行緒的數量就應該是核心數量的2倍。如果更少的比例被阻塞,那麼它們就是計算密集型的,則需要開闢較少的執行緒。如果有更多的時間被阻塞,那麼就是IO密集型的程式,則可以開闢更多的執行緒。於是我們可以得到下面的執行緒數量計算公式:
執行緒數量=核心數量 / (1 - 阻塞率)
我們可以通過相應的分析工具或者java的management包來得到阻塞率的數值。