前言
線程是比進程更輕量級的調度執行單位,線程的引入,可以把一個進程的資源分配和執行調度分開,各個線程既可以共享進程資源(內存地址、文件I/O等),又可以獨立調度(線程是CPU調度的基本單位)。JAVA語言中每個已經執行了 start() 且還未結束的 java.lang.Thread 類的實例就代表了一個線程。Thread 類的所有關鍵方法都是聲明為Native的,在Java API中,一個Native方法往往意味著這個方法沒有使用或者無法使用平臺無關的手段來實現(也可能為了執行效率)。
1. 線程的實現
實現線程主要有3種方法:內核線程、用戶線程、用戶線程加輕量級進程混合實現。
1.1 使用內核線程實現
內核線程(Kernel-Level Thread, KLT)就是由操作系統內核支持的線程,內核通過操作調度器(Scheduler)對線程進行調度。
程序一般不會直接使用內核線程,而是去使用內核線程的一種高級接口-輕量級進程(Light Weight Process, LWP),輕量級進程就是我們通常意義上所講的線程。
這種輕量級進程與內核線程之間1:1的關系稱為一對一的線程模型,如下圖。
優點: 每個輕量級進程都成為一個獨立的調度單元,即使有一個輕量級進程在系統中阻塞了,也不會影響整個進程繼續工作。缺點: 由于是基于內核線程實現的,所以各種線程操作,如創建、析構及同步,都需要進行系統調用,需要在用戶態和內核態中來回切換,代價相對較高。
1.2 使用用戶線程實現
用戶線程(User Thread, UT)指的是完全建立在用戶空間的線程庫上,系統內核不能感知線程存在的實現。
用戶線程的建立、同步、銷毀和調度完全在用戶態中完成,不需要內核的幫助。因此操作比內核線程更快速,并可以支持更大的線程數量。
這種進程(不是輕量級進程)與用戶線程之間1:N的關系稱為一對多的線程模型。
優點: 線程所有操作都在用戶態完成,不需要切換到內核態,如果實現得當,那么速度非???,資源消耗也很低,可以支持更大規模的線程數量。
缺點: 由于線程的操作沒有操作系統內核的支援,所有線程操作都需要用戶程序自己實現,創建、線程間的切換、調度都需要用戶程序處理,并且由于操作系統只把處理器資源分配到了進程,除了線程切換獲取處理器外,線程阻塞如何處理,或者把進程內的線程映射到其他處理器,都是非常困難的。
現在使用用戶線程的程序越來越少了,像Java、Ruby等語言都曾經使用過用戶線程,不過現在都放棄了。
1.3 使用用戶線程加輕量級進程混合實現
在這種混合實現下,既存在用戶線程,也存在輕量級進程。
用戶線程還是完全建立在用戶空間中,因此用戶線程的創建、切換、析構等操作依然廉價。而操作系統提供輕量級進程則作為用戶線程和內核線程之間的橋梁。這樣可以使用內核提供的線程調度功能及處理器映射,用戶線程調用通過輕量級線程來完成。
用戶線程與輕量級進程的數量比是不定的,即為N:M的關系,這種就是多對多的線程模型。
2. Java 線程的實現
Java 線程在JDK 1.2之前,是基于用戶線程實現的,JDK 1.2中替換為基于操作系統原生線程模型來實現。目前的JDK版本中,操作系統支持怎樣的線程模型,很大程序上決定了Java虛擬機的線程是怎樣映射的。
虛擬機規范中并未限定Java線程需要使用哪種線程模型來實現。
對于Sun JDK來說,它的windows版與linux版都是使用一對一的線程模型實現的,一條Java線程映射到一條輕量級進程中,即內核線程的實現方式。
3. Java 線程的調度
線程調度是指系統為線程分配處理器使用權的過程。主要有協同式線程調度和搶占式線程調度兩種。
如果使用協同式調度的多線程系統,線程的執行時間由線程本身來控制,線程把自己的工作執行完了之后,要主動通知系統切換到另外一個線程上。如果一個線程寫得有問題,一直不告知系統進行線程切換,那么程序就會一直阻塞在那里。
如果使用搶占式調度的多線程系統,那么每個線程將由系統來分配執行時間,線程的切換不由線程本身來決定。
Java 使用的線程調度方法就是搶占式調度。






