Thread類詳解 多執行緒中篇(二)
Java.lang.Thread是Java應用程式設計師對Java多執行緒的第一站, Thread就是對Java執行緒本身的抽象
所以在Java中的執行緒程式設計概念中, 一個Thread例項 == 一個執行緒
執行緒有哪些屬性、行為,Thread大致就有哪些屬性、行為。
前文中有說到,Java執行緒通過Thread以及synchronized以及Object中的wait等對“控制、同步、通訊”進行了抽象,synchronized關鍵字是同步,Object中的相關方法是通訊,Thread中的資訊主要是控制以及自身的行為,但是比如join方法,也可以被認為是用於“通訊”,所以不要一概而論,也不要咬文嚼字,要注重背後的思維
Thred概述
執行緒也是對程式執行的抽象描述,所以執行緒包括兩部分資訊:
- 一個是執行緒自身資料(元資料)
- 另一個是將要執行的任務
自身資料又分為必備的控制資訊以及行為。
也就是說一個Thread包括了三方面的資訊:基本資訊、執行緒自身的行為、執行緒任務
基本資訊
如下圖所示,基本資訊包括下面這些
- 名稱、id、優先順序、狀態、執行緒組、守護執行緒狀態、堆疊資訊跟蹤
- 上下文類載入器設定、異常處理器設定
- 是否存活、當前執行緒是否有權修改該執行緒
名稱
執行緒是有名稱的,有屬性name,如果不指定名稱,那麼會生成thread-0,thread-1..........thread-N這種名稱
ID
如果類比到人的話,名稱就是姓名,而ID就是身份證號,執行緒也有一個唯一的識別符號
執行緒 ID 是一個正的 long 數,在建立該執行緒時生成,執行緒 ID 是唯一的,並終生不變
執行緒終止時,該執行緒 ID 可以被重新使用
在私有方法init方法中設定
優先順序
執行緒內部priority記錄優先順序
如果設定的值不在有效範圍內,直接丟擲異常
否則執行緒的優先順序會被設定為“指定的 newPriority 和 該執行緒的執行緒組允許的最大優先順序”兩者中較小的那一個。
簡單說就是不能超過執行緒組的最大優先順序,你工資再高也超不過你領導......
執行緒預設的優先順序是NORM_PRIORITY=5,一般情況下不需要設定優先順序
因為你設定了優先順序並不一定總是完全按照你的想法進行, 前面說過,Java執行緒是作業系統原生執行緒的對映,要依賴作業系統
所以,萬萬不要業務邏輯依賴你自以為的執行緒優先順序
狀態
類似程序,執行緒也是有專門的狀態的
有內部類State
執行緒組
執行緒組用於對執行緒進行管理,ThreadGroup
執行緒組表示一個執行緒的集合。此外,執行緒組也可以包含其他執行緒組
執行緒組構成一棵樹,在樹中,除了初始執行緒組外,每個執行緒組都有一個父執行緒組
守護執行緒狀態
可以將一個Thread標記為守護執行緒
守護執行緒,可以認為是後臺執行緒
如果沒有任何一個非守護執行緒在執行,或者說在執行的執行緒都是守護執行緒,JVM將退出。
全都是服務員,一個客人都沒有,那還忙活個屁?
需要注意的是,必須是執行緒啟動前設定,不然你試試看,分分鐘 throw new IllegalThreadStateException();
因為已啟動尚未終止的就是isAlive==true
堆疊資訊跟蹤
簡單的可以理解為執行緒執行時有一個“呼叫棧資訊”,後續介紹
上下文類載入器設定
除非特別設定,否則contextClassLoader將會設定為與父執行緒同樣的值。
上線文類載入器是類載入機制的後門,打破了雙親委派模型,此處不對上下文類載入器進行介紹,也是一個比較重要的知識點。
異常處理器設定
執行緒在執行單元中是不允許丟擲checked異常的,而且執行緒執行在自己的上下文中,派生它的執行緒將無法直接獲得它執行中出現的異常資訊。
所以Java為我們提供異常處理器回撥機制,異常處理器的設定就是這個作用
是否存活
執行緒從啟動之後,直到最終終止,這一個過程被稱之為是活動狀態
換句話說,一個執行緒start之後,除非他被終止,否則任何時刻都是true
isAlive就是用於檢測執行緒是否處於活動狀態
當前執行緒是否有權修改該執行緒
判定當前執行的執行緒是否有權修改該執行緒。
比如執行緒Thread aThread,在main方法中呼叫aThread.checkAccess,此時當前執行緒是主執行緒main,目標是aThread
那麼就是檢測主執行緒是否有權利修改執行緒aThread
執行緒行為
Thread中的方法,有一些是執行緒本身的行為控制或者通訊,另外還有一些相當於是工具類
還有一些被棄用了
currentThread
返回對當前正在執行的執行緒物件的引用,執行緒是Thread,哪個Thread正在執行,那麼就返回哪個物件就好了,返回型別就是Thread
activeCount
返回的是當前執行緒,所在的執行緒組中,活動執行緒的個數
enumerate
執行緒的抽象是Thread,每一個執行緒都是一個Thread,既然是物件那麼就有類似尋常物件的操作,比如儲存到陣列
enumerate就是用來講當前執行緒的、所屬執行緒組中的、以及子組中的每一個活動執行緒複製到指定的陣列中,返回值為複製的執行緒的個數
依賴於執行緒組中的相關方法
是否持有指定監視器的鎖
如同前面提到過的互斥量,Java中同步時需要用到一個物件鎖,如果一個執行緒請求的鎖被別的執行緒獲得,那麼就需要進行等待,持有了鎖就可以進入臨界區。
方法用於判斷當前執行緒,當前執行緒、當前執行緒。針對於某個物件,是否持有對應的鎖,當且僅當當前執行緒在指定的物件上保持監視器鎖時,才返回 true。
如果 obj 為 null,丟擲NPE
dumpStack
用於除錯,將當前執行緒的資訊列印到標準錯誤流
執行緒任務
執行緒的任務核心是Runnable,內部持有一個Runnable target,構造時如果不進行設定那麼為null
呼叫start方法啟動後,會呼叫run方法,如果不重寫run方法,或者構造時不程序傳遞,那麼target為null
很顯然如果target,run方法就相當於一個空方法,也就是什麼都不做。
簡言之,Java對於執行緒以及執行緒任務,進行了抽象分離,對執行緒的抽象為Thread,而對於執行緒任務的抽象就是Runnable。
總結
Thread是Java對執行緒的抽象,所以他的屬性資訊自然與執行緒的概念是不謀而合和,本文對Thread中定義的一些屬性進行了簡單介紹,有些後續還會詳細進行介紹
Thread中的方法主要用於對執行緒進行控制也可以用作通訊,還有一些是基於類設計層面的,新增進來的一些工具類,可以對執行緒的一些資訊進行控制、獲取
執行緒任務是通過Runnable進行抽象,簡言之,Thread表示執行緒,Runnable表示任務。
“分別是為了更好地重逢”放到這裡非常合適,解耦是為了更好地協作。
執行緒本身和執行緒需要執行的任務進行分離,無論是從抽象概念上還是認知理解上,亦或者是二者獨立的發展上,解耦都有多種好處
徹底認清楚Thread的本質--執行緒概念的抽象,才能夠更好的瞭解Thread中那些屬性欄位
比如你完全不瞭解IEEE754,何談對Float的實現熟悉?概念都不清晰,哪來的清晰地實現?
Thread是對執行緒的抽象,封裝了執行緒具有的一些屬性和狀態以及行為資訊,具體就是體現在內部的欄位和方法上,另外還有一些相當於工具類的存在的方法,也是構建在Thread中的,所以執行緒是Thread,Thread是執行緒概念的體現。
不管JVM內部如何對映,作業系統如何構建執行緒模型,Java開發者接觸的就是Thread的例項物件。
在Java這一面向物件的語言中,多執行緒程式設計就是“多Thread物件程式設計”
我們常說Java是純粹的面向物件的程式語言,什麼“封裝、繼承、多型”等等的,但是真的理解了面向物件的思維了麼?這就是面向物件!萬事萬物都是物件