摘要:線程的可能實現方式基本上主流的操作系統都支持線程,也提供了線程的實現。使用用戶線程和內核線程混合實現在這種混合實現下,既存在用戶線程,也存在內核線程。
進程與線程
在傳統的操作系統中,最核心的概念是“進程”,進程是對正在運行的程序的一個抽象。
進程的存在讓“并行”成為了可能,在一個操作系統中,允許運行著多個進程,這些進程“看起來”是同時在運行的。
如果我們的計算機同時運行著 web 瀏覽器、電子郵件客戶端、即時通訊軟件例如QQ微信等多個進程,我們感覺這些進程都是同時在運行的,假設這臺計算機搭配的是多個 CPU 或者 多核 CPU,那么這種多個進程并行的現象可能一點也不奇怪,完全可以為每個進程多帶帶分配一個 CPU,這樣就實現了多進程并行。
然而事實上,在計算機只有一個 CPU 的情況下,它也能給人類一種感覺:多個進程同時在運行。但人類的感覺往往是比較模糊的,不精確的。事實是由于 CPU 的計算速度非常地快,它能快速地在各個進程之間切換,在某一瞬間,CPU 只能運行一個進程,但一秒鐘之內,它就能通過快速切換,讓人產生多個進程同時在運行的錯覺。
在操作系統中,為什么在進程的基礎上,又衍生出了線程的概念呢?
由于對于一些進程而言,它內部會發生多種活動,有些活動可能會在某個時間里阻塞,有些活動不會,如果通過線程將這些活動分離開使它們能夠并行地運行,則設計程序的時候會更加簡單。
線程比進程的創建更加輕量級,性能消耗更少
如果一個進程既需要 CPU 計算,也需要I/O處理,擁有多線程允許這些活動重疊進行,加快整個進程的執行速度。
每一個進程在操作系統中都擁有獨立的一塊內存地址空間,該進程創建的所有線程共享這塊內存,支持多線程的操作系統,會讓線程作為 CPU 調度的最小單位。CPU 的時間片在不同的線程之間進行分配。
線程的可能實現方式基本上主流的操作系統都支持線程,也提供了線程的實現。而 Java 語言為了應對不同硬件和操作系統的差異,提供了對線程操作的統一抽象,在 Java 中我們使用 Thread 類來代表一個線程。
Thread 的具體實現可能會有不同的實現方式:
內核線程是操作系統內核支持的線程,在內核中有一個線程表用來記錄系統中的所有線程,創建或者銷毀一個線程時,都需要涉及到系統調用,然后再內核中對線程表進行更新操作。對內核線程的阻塞以及其它操作,都涉及到系統調用,系統調用的代價都比較大,涉及到在用戶態和內核態之間的來回切換。此外,內核內部有線程調度器,用于決定應該將 CPU 時間片分配個哪個線程。
程序一般不會直接操作內核線程,而是使用內核線程的一種高級接口,輕量級進程。輕量級進程與內核線程之間的關系是 1:1,每一個輕量級進程內部都有一個內核線程支持。
上圖中, LWP 指 Light Weight Process,即輕量級進程;KLT 指 Kernel Level Thread,即內核線程。
使用用戶線程實現用戶線程是程序或者編程語言自己實現的線程庫,系統內核無法感知到這些線程的存在。用戶線程的建立、同步、銷毀和調度,都在用戶態中完成,無須內核的幫助,不需要進行系統調用,這樣的好處是對于線程的操作是非常高效的。在這種情況下,進程和用戶線程的比例是 1 :N。
用戶態線程面對如何阻塞線程時,會面臨困難,阻塞一個用戶態線程會出現把整個進程都阻塞的情況,多線程也就失去了意義。因為缺少內核的支持,所以很多需要利用內核才能完成的工作,例如阻塞與喚醒線程、多 CPU 環境下線程的映射等,都需要用戶程序去實現,實現起來會異常困難。
使用用戶線程和內核線程混合實現在這種混合實現下,既存在用戶線程,也存在內核線程。用戶態線程的創建、切換這些操作依然很高效,并且用戶態實現的線程,比較容易加大線程的規模。需要操作系統內核支持的功能,則通過內核線程來做到,例如映射到不同的處理器上、處理線程的阻塞與喚醒以及內核線程的調度等。這種實現依然會使用到輕量級進程 LWP,它是用戶線程和內核線程之間的橋梁。
Java 線程的實現在 JDK1.2 之前, Java 的線程是使用用戶線程實現的,在 JDK1.2 之后,Java 才采用操作系統原生支持的線程模型來實現,Java 線程模型的實現方式,主要取決于操作系統。對于 Oracle JDK 來說,在 Windows 和 Linux 上的線程模型是采用一對一的方式實現的,即一條 Java 線程映射到一條輕量級進程(內核線程)。而在 Solaris 平臺中,Java 則支持 1 :1 和 N : M 的線程模型。
線程的阻塞與等待Java 中的線程的狀態有以下幾種:New,Runnable,Waiting, TimedWaiting, Blocked,Terminated。
NEW:線程初創建,未運行
RUNNABLE:線程正在運行,但不一定消耗 CPU
BLOCKED:線程正在等待另外一個線程釋放鎖
WAITING:線程執行了 wait, join, LockSupport.park() 方法
TIMED_WAITING:線程調用了sleep, wait, join, LockSupport.parkNanos() 等方法,與 WAITING 狀態不同的是,這些方法帶有表示時間的參數。
其中 Blocked 和 Waiting 有個重要的區別是,阻塞(Blocked)狀態的線程在等待獲取一個排他鎖,例如線程在等待進入一個synchronized關鍵字包圍的臨界區時,就進入 Blocked 狀態。而 Waiting 狀態則是在等待被喚醒,或者等待一段時間。
參考資料《深入理解 Java 虛擬機》第二版 - 周志明
《現代操作系統》第四版 - Andrew S. Tanenbaum
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77139.html
摘要:大多數待遇豐厚的開發職位都要求開發者精通多線程技術并且有豐富的程序開發調試優化經驗,所以線程相關的問題在面試中經常會被提到。掌握了這些技巧,你就可以輕松應對多線程和并發面試了。進入等待通行準許時,所提供的對象。 最近看到網上流傳著,各種面試經驗及面試題,往往都是一大堆技術題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關線程的問題。Java語言一個重要的特點就...
摘要:并發編程實戰水平很高,然而并不是本好書。一是多線程的控制,二是并發同步的管理。最后,使用和來關閉線程池,停止其中的線程。當線程調用或等阻塞時,對這個線程調用會使線程醒來,并受到,且線程的中斷標記被設置。 《Java并發編程實戰》水平很高,然而并不是本好書。組織混亂、長篇大論、難以消化,中文翻譯也較死板。這里是一篇批評此書的帖子,很是貼切。俗話說:看到有這么多人罵你,我就放心了。 然而知...
摘要:例子如下可以用如下方式創建并運行上述子類一旦線程啟動后方法就會立即返回,而不會等待到方法執行完畢才返回。但是,事實上方法并非是由剛創建的新線程所執行的,而是被創建新線程的當前線程所執行了。這是因為線程是并行執行而非順序的。 showImg(http://segmentfault.com/img/bVbN5u); Java線程類也是一個object類,它的實例都繼承自java.lang...
閱讀 3087·2021-10-12 10:20
閱讀 2820·2021-09-27 13:56
閱讀 796·2021-09-27 13:36
閱讀 1436·2021-09-26 09:46
閱讀 2422·2019-08-30 14:02
閱讀 2691·2019-08-28 18:14
閱讀 1268·2019-08-26 10:32
閱讀 1710·2019-08-23 18:25