Java的線程模型

并發不一定要依賴多線程(如PHP中很常見的多進程并發),但是在Java里面談論并發,大多數都與線程脫不開關系。

線程是比進程更輕量級的調度執行單位,線程的引入,可以把一個進程的資源分配執行調度分開,各個線程既可以共享進程資源(內存地址、文件I/O等),又可以獨立調度(線程是CPU調度的基本單位)。

主流的操作系統都提供了線程實現,Java語言則提供了在不同硬件和操作系統平臺下對線程操作的統一處理,每個已經執行start()且還未結束的java.lang.Thread類的實例就代表了一個線程。我們注意到Thread類與大部分的Java API有顯著的差別,它的所有關鍵方法都是聲明為Native的。在Java API中,一個Native方法往往意味著這個方法沒有使用或無法使用平臺無關的手段來實現(當然也可能是為了執行效率而使用Native方法,不過,通常最高效率的手段也就是平臺相關的手段)。

線程的實現

實現線程主要有3種方式:使用內核線程實現、使用用戶線程實現和使用用戶線程加輕量級進程混合實現。

使用內核線程實現

內核線程(Kernel-Level Thread,KLT)就是直接由操作系統內核(Kernel,下稱內核)支持的線程,這種線程由內核來完成線程切換,內核通過操縱調度器(Scheduler)對線程進行調度,并負責將線程的任務映射到各個處理器上。每個內核線程可以視為內核的一個分身,這樣操作系統就有能力同時處理多件事情,支持多線程的內核就叫做多線程內核(Multi-Threads Kernel)。

程序一般不會直接去使用內核線程,而是去使用內核線程的一種高級接口——輕量級進程(Light Weight Process,LWP),輕量級進程就是我們通常意義上所講的線程,由于每個輕量級進程都由一個內核線程支持,因此只有先支持內核線程,才能有輕量級進程。這種輕量級進程與內核線程之間1:1的關系稱為一對一的線程模型。

由于內核線程的支持,每個輕量級進程都成為一個獨立的調度單元,即使有一個輕量級進程在系統調用中阻塞了,也不會影響整個進程繼續工作,但是輕量級進程具有它的局限性:

首先,由于是基于內核線程實現的,所以各種線程操作,如創建、析構及同步,都需要進行系統調用。而系統調用的代價相對較高,需要在用戶態(User Mode)和內核態(Kernel Mode)中來回切換。

其次,每個輕量級進程都需要有一個內核線程的支持,因此輕量級進程要消耗一定的內核資源(如內核線程的棧空間),因此一個系統支持輕量級進程的數量是有限的。

使用用戶線程實現

從廣義上來講,一個線程只要不是內核線程,就可以認為是用戶線程(User Thread,UT),因此,從這個定義上來講,輕量級進程也屬于用戶線程,但輕量級進程的實現始終是建立在內核之上的,許多操作都要進行系統調用,效率會受到限制。

而狹義上的用戶線程指的是完全建立在用戶空間的線程庫上,系統內核不能感知線程存在的實現。用戶線程的建立、同步、銷毀和調度完全在用戶態中完成,不需要內核的幫助。如果程序實現得當,這種線程不需要切換到內核態,因此操作可以是非常快速且低消耗的,也可以支持規模更大的線程數量,部分高性能數據庫中的多線程就是由用戶線程實現的。這種進程與用戶線程之間1:N的關系稱為一對多的線程模型。

使用用戶線程的優勢在于不需要系統內核支援,劣勢也在于沒有系統內核的支援,所有的線程操作都需要用戶程序自己處理。線程的創建、切換和調度都是需要考慮的問題,而且由于操作系統只把處理器資源分配到進程,那諸如“阻塞如何處理”、“多處理器系統中如何將線程映射到其他處理器上”這類問題解決起來將會異常困難,甚至不可能完成。因而使用用戶線程實現的程序一般都比較復雜,此處所講的“復雜”與“程序自己完成線程操作”,并不限制程序中必須編寫了復雜的實現用戶線程的代碼,使用用戶線程的程序,很多都依賴特定的線程庫來完成基本的線程操作,這些復雜性都封裝在線程庫之中,除了以前在不支持多線程的操作系統中(如DOS)的多線程程序與少數有特殊需求的程序外,現在使用用戶線程的程序越來越少了,Java、Ruby等語言都曾經使用過用戶線程,最終又都放棄使用它。

使用用戶線程加輕量級進程混合實現

線程除了依賴內核線程實現和完全由用戶程序自己實現之外,還有一種將內核線程與用戶線程一起使用的實現方式。在這種混合實現下,既存在用戶線程,也存在輕量級進程。用戶線程還是完全建立在用戶空間中,因此用戶線程的創建、切換、析構等操作依然廉價,并且可以支持大規模的用戶線程并發。而操作系統提供支持的輕量級進程則作為用戶線程和內核線程之間的橋梁,這樣可以使用內核提供的線程調度功能及處理器映射并且用戶線程的系統調用要通過輕量級線程來完成,大大降低了整個進程被完全阻塞的風險。在這種混合模式中,用戶線程與輕量級進程的數量比是不定的,即為N:M的關系。許多UNIX系列的操作系統,如Solaris、HP-UX等都提供了N:M的線程模型實現。

Java線程的實現

對于Sun JDK來說,它的Windows版與Linux版都是使用一對一的線程模型實現的,一條Java線程就映射到一條輕量級進程之中,因為Windows和Linux系統提供的線程模型就是一對一的

在Solaris平臺中,由于操作系統的線程特性可以同時支持一對一(通過Bound Threads或Alternate Libthread實現)及多對多(通過LWP/Thread Based Synchronization實現)的線程模型,因此在Solaris版的JDK中也對應提供了兩個平臺專有的虛擬機參數:-XX:+UseLWPSynchronization(默認值)和-XX:+UseBoundThreads來明確指定虛擬機使用哪種線程模型。

Java線程調度

線程調度是指系統為線程分配處理器使用權的過程,主要調度方式有兩種,分別是協同式線程調度(Cooperative Threads-Scheduling)和搶占式線程調度(Preemptive Threads-Scheduling)。

協同式調度

如果使用協同式調度的多線程系統,線程的執行時間由線程本身來控制,線程把自己的工作執行完了之后,要主動通知系統切換到另外一個線程上。協同式多線程的最大好處是實現簡單,而且由于線程要把自己的事情干完后才會進行線程切換,切換操作對線程自己是可知的,所以沒有什么線程同步的問題。Lua語言中的“協同例程”就是這類實現。它的壞處也很明顯:線程執行時間不可控制,甚至如果一個線程編寫有問題,一直不告知系統進行線程切換,那么程序就會一直阻塞在那里。很久以前的Windows 3.x系統就是使用協同式來實現多進程多任務的,相當不穩定,一個進程堅持不讓出CPU執行時間就可能會導致整個系統崩潰。

搶占式調度

如果使用搶占式調度的多線程系統,那么每個線程將由系統來分配執行時間,線程的切換不由線程本身來決定(在Java中,Thread.yield()可以讓出執行時間,但是要獲取執行時間的話,線程本身是沒有什么辦法的)。在這種實現線程調度的方式下,線程的執行時間是系統可控的,也不會有一個線程導致整個進程阻塞的問題,Java使用的線程調度方式就是搶占式調度。在JDK后續版本中有可能會提供協程(Coroutines)方式來進行多任務處理。與前面所說的Windows 3.x的例子相對,在Windows 9x/NT內核中就是使用搶占式來實現多進程的,當一個進程出了問題,我們還可以使用任務管理器把這個進程“殺掉”,而不至于導致系統崩潰。

線程優先級

雖然Java線程調度是系統自動完成的,但是我們還是可以“建議”系統給某些線程多分配一點執行時間,另外的一些線程則可以少分配一點——這項操作可以通過設置線程優先級來完成。Java語言一共設置了10個級別的線程優先級(Thread.MIN_PRIORITY至Thread.MAX_PRIORITY),在兩個線程同時處于Ready狀態時,優先級越高的線程越容易被系統選擇執行。不過,線程優先級并不是太靠譜,原因是Java的線程是通過映射到系統的原生線程上來實現的,所以線程調度最終還是取決于操作系統,雖然現在很多操作系統都提供線程優先級的概念,但是并不見得能與Java線程的優先級一一對應,如Solaris中有2147483648(232)種優先級,但Windows中就只有7種,比Java線程優先級多的系統還好說,中間留下一點空位就可以了,但比Java線程優先級少的系統,就不得不出現幾個優先級相同的情況了,表12-1顯示了Java線程優先級與Windows線程優先級之間的對應關系,Windows平臺的JDK中使用了除THREAD_PRIORITY_IDLE之外的其余6種線程優先級。

上文說到“線程優先級并不是太靠譜”,不僅僅是說在一些平臺上不同的優先級實際會變得相同這一點,還有其他情況讓我們不能太依賴優先級:優先級可能會被系統自行改變。例如,在Windows系統中存在一個稱為“優先級推進器”(Priority Boosting,當然它可以被關閉掉)的功能,它的大致作用就是當系統發現一個線程執行得特別“勤奮努力”的話,可能會越過線程優先級去為它分配執行時間。因此,我們不能在程序中通過優先級來完全準確地判斷一組狀態都為Ready的線程將會先執行哪一個。

線程狀態轉換

Java語言定義了5種線程狀態,在任意一個時間點,一個線程只能有且只有其中的一種狀態,這5種狀態分別如下。

  1. 新建(New):創建后尚未啟動的線程處于這種狀態。
  2. 運行(Runable):Runable包括了操作系統線程狀態中的Running和Ready,也就是處于此狀態的線程有可能正在執行,也有可能正在等待著CPU為它分配執行時間。
  3. 無限期等待(Waiting):處于這種狀態的線程不會被分配CPU執行時間,它們要等待被其他線程顯式地喚醒。以下方法會讓線程陷入無限期的等待狀態:
    • 沒有設置Timeout參數的Object.wait()方法。
    • 沒有設置Timeout參數的Thread.join()方法。
    • LockSupport.park()方法。

  4.限期等待(Timed Waiting):處于這種狀態的線程也不會被分配CPU執行時間,不過無須等待被其他線程顯式地喚醒,在一定時間之后它們會由系統自動喚 ? ? ? ? ? ?醒。以下方法會讓線程進入限期等待狀態:

    • Thread.sleep()方法。
    • 設置了Timeout參數的Object.wait()方法。
    • 設置了Timeout參數的Thread.join()方法。
    • LockSupport.parkNanos()方法。
    • LockSupport.parkUntil()方法。

  5.阻塞(Blocked):線程被阻塞了,“阻塞狀態”與“等待狀態”的區別是:“阻塞狀態”在等待著獲取到一個排他鎖,這個事件將在另外一個線程放棄這個鎖的時候 ? ? ? ? ? ?發生;而“等待狀態”則是在等待一段時間,或者喚醒動作的發生。在程序等待進入同步區域的時候,線程將進入這種狀態。

  6.結束(Terminated):已終止線程的線程狀態,線程已經結束執行。

?

轉載于:https://www.cnblogs.com/wade-luffy/p/6051384.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254013.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254013.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254013.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

BT656/BT601/BT1120協議以及DM365/DM355/DM6467上使用的YUV顏色空間說明

ITU-R BT.601和ITU-RBT.656國際電信聯盟(International Telecommunication Union)無線通信部門(ITU-R)制定的標準。嚴格來說,ITU-R BT.656應該是隸屬ITU-R BT.601的一個子協議。ITU-R BT.601是演播室數字電視編碼參數標…

eclispe設置workspace text file encoding

在windows下開發,經常會遇到eclipse新導入的工程 java代碼中的注釋或者字符串中文顯示亂碼,每次都要一個個項目更改麻煩,特地找了下,可通過如下方法一次性設置。 轉載于:https://www.cnblogs.com/zhjh256/p/7190537.html

工業定焦鏡頭的選型公式

工業鏡頭的焦距(f mm)可以根據FOV(視場), WD(工作距離) 和CCD芯片尺寸計算出來:FOV視場指被攝取物體的大小,視場的大小是以鏡頭至被攝取物體距離(WD),鏡頭焦距(F)及CCD芯片尺寸確定的。鏡頭的焦距,視場大小、工作距離、光學倍率計算如下:焦距…

Nginx系列二:(Nginx Rewrite 規則、Nginx 防盜鏈、Nginx 動靜分離、Nginx+keepalived 實現高可用)...

一、Nginx Rewrite 規則 1. Nginx rewrite規則 Rewrite規則含義就是某個URL重寫成特定的URL&#xff08;類似于Redirect&#xff09;&#xff0c;從某種意義上說為了美觀或者對搜索引擎友好&#xff0c;提高收錄量及排名等。 語法&#xff1a; rewrite<regex><replace…

受限玻爾茲曼機(RBM)以及對比散度(CD)

1. RBM 的提出 BM 的缺點&#xff1a; 計算時間漫長&#xff0c;尤其是無約束自由迭代的負向階段&#xff1b;對抽樣噪音敏感&#xff1b;流行軟件的不支持&#xff1b;受限玻爾茲曼機&#xff08;Restricted Boltzmann Machine,簡稱 RBM&#xff0c;以解決 BM 的學習效率過慢的…

嵌入式系統中看門狗概述。。。

一直以來對于嵌入式中的watch dog&#xff08;看門狗&#xff09;都比較陌生&#xff0c;一直都不知道它到底是做什么的&#xff0c;單從名字上看也不知其所以然&#xff0c;然后就在網上找到了一篇blog&#xff0c;就是再說看門狗的作用和概述&#xff0c;原文如下&#xff1a…

MySQL中的運算符

算術運算符 MySQL 支持常見的五種算術運算&#xff1a;, -, *, /(同 DIV 函數), %(同 MOD 函數)&#xff0c;即加減乘除和取余。&#xff08;被除數為 0則結果為 NULL&#xff09; 比較運算符 當使用 SELECT 語句進行查詢時&#xff0c;MySQL 允許用戶對表達式的左邊操作數和右…

Qt中查看ui_xxx.h文件方法

前提 1、Qt當有界面 2、構造完成 滿足以上兩個條件qt會生成ui_xxx.h文件。 如何查看 方法1 在cpp文件中找到UI下的一個對象 如&#xff1a; ui->textEdit Ui::QWDialog按住Ctrl鍵&#xff0c;使用鼠標左鍵點擊UI下的一個對象&#xff0c;如&#xff1a;textEdit、QWDia…

springCloud Finchley 實戰入門(基于springBoot 2.0.3)【三 Eureka-高可用服務注冊中心】...

Eureka高可用注冊中心 Eureka Server的設計一開始就考慮到了高可用的問題&#xff0c;在eureka服務治理設計中&#xff0c;所有的節點即是是服務提供方&#xff0c;也是服務消費方。 在部署高可用注冊中心前我們先需要準備一下&#xff0c;本地環境。因為我們實例是在單臺電腦上…

Spring 讀取配置文件(二)

Spring 讀取配置文件并調用 bean package cn.com.test.receive;import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class…

DaVinci的Buffer_Handle和BufTab Cmem函數調用

DaVinci的dvsdk里面&#xff0c;所有的內存用的都是CMEM&#xff0c;而比較上層的一個封裝就是BufTab和Buffer_Handle了 每個Tab可以控制好多塊內存塊。 具體到內存塊有兩種&#xff0c;一種是創建的時候指定他的大小啊&#xff0c;物理地址啥的。另外一種就是僅僅創建出這個 …

Qt使用兩組RadioButton,兩組之間相互獨立

Qt中使用兩組共四個RadioButton時&#xff0c;由于RadioButton的特性&#xff0c;所以兩組一共四個按鈕每次只能選擇一個&#xff0c;要使得兩組RadioButton相互獨立&#xff0c;需要用到QButtonGroup這個功能&#xff0c;把RadioButton加到QButtonGroup里面&#xff0c;實現兩…

sleep 和 wait 的區別

為什么80%的碼農都做不了架構師&#xff1f;>>> 面試中常問的就是 sleep 和 wait 有什么不同嗎&#xff1f;為了面試時候發揮的更好&#xff0c;我在這里總結分享下。 首先對于 sleep() 方法&#xff0c;我們首先要知道該方法是屬于 Thread 類中的。而 wait() 方法…

2016年11月13日周工作知識點總結

jQuery :eq() 選擇器選取帶有指定 index 值的元素。index 值從 0 開始&#xff0c;所有第一個元素的 index 值是 0&#xff08;不是 1&#xff09;。經常與其他元素/選擇器一起使用&#xff0c;來選擇指定的組中特定序號的元素&#xff08;如下面的例子&#xff09;。$("p…

DM6467之視頻采集(Linux)下MMAP

做&#xff44;&#xff53;&#xff50;&#xff16;&#xff14;&#xff16;&#xff17;是在linux下做視頻采集&#xff0c;僅ARM端 一共有三種視頻采集方式&#xff1a; 1&#xff09;使用read、write方式&#xff1a;直接使用 read 和 write 函數進行讀寫。這種方式最簡…

QPS、TPS計算

QPS (Query per second) &#xff08;每秒查詢量&#xff09; TPS(Transaction per second) &#xff08;每秒事務量&#xff0c;如果是InnoDB會顯示&#xff0c;沒有InnoDB就不會顯示&#xff09; 計算方法 QPS Questions SHOW GLOBAL STATUS LIKE Questions; Uptime SHOW G…

QT 中textEdit 和 textBrowser 無法使用斜體及加粗等 解決辦法

編輯框的幾個種類 QT 中一共四個文本編輯框 分別是 Line Edit 、Text Edit、 Plait Text Edit和textBrowser四種文本編輯框架&#xff01; 一、輸入內容不同 1、LineEdit&#xff1a;LineEdit的輸入內容為單行文本輸入。 2、TextEdit&#xff1a;TextEdit的輸入內容為多行文…

【select模塊】select IO多路復用和select實現FTP

select是全平臺通用的IO多路復用模塊。最大連接數&#xff1a;1024。poll和epoll沒有最大連接數限制&#xff0c;但只能用在linux平臺。selectors是再封裝模塊&#xff0c;推薦使用。下篇會討論。select.select(rlist, wlist, xlist[, timeout])This is a straightforward inte…

變量屬性

變量屬性 C語言的變量屬性 C語言中的變量可以有自己的屬性在定義變量的時候加上“屬性”關鍵字屬性關鍵字指明變量的特有意義auto關鍵字 auto即C語言中局部變量的默認屬性auto表明將被修飾的變量存儲在棧上編譯器默認所有的局部變量都是auto的register關鍵字 register關鍵字指明…

WPF:How to display a Bitmap on Image control

一個Bitmap文件&#xff0c;叫做screenShotFile, 你可以這樣顯示到Image控件上。 BitmapImage bi new BitmapImage(); bi.BeginInit(); bi.UriSource new Uri(this.screenShotFile, UriKind.Absolute); bi.EndInit(); this.scre…