java多線程核心技術---學習筆記 頂 原

1.java多線程技能

1.1.進程和多線程的概念及線程的優點

進程:進程是操作系統的基礎,是一次程序的執行,是一個程序及數據在處理機上順序執行時所發生的活動。是程序在一個數據集合上運行的過程,他是系統進行資源分配和調度的一個獨立單位。

線程:進程中獨立運行的子任務。

多線程優點:最大限度的利用CPU的空閒時間來處理其他子任務。

1.2. 使用多線程

直接使用java main方法運行程序,也運行了一個線程。一個進程至少有一個線程在運行。

實現多線程的方式主要有兩種: 繼承Thread類,實現Runnable接口。其實Thread 也是實現了Runnable接口,兩者沒有本質的區別。

直接啓動run方法,沒有異步效果,即使起了很多線程也會是單線程執行的模式,指向start方法纔會異步執行,將線程對象交給線程規劃器執行。

執行start的順序,不代表線程啓動的順序,start方法只是通知線程調度器此線程已經準備就緒,具體順序由jvm控制。

爲了可以繼承其他的類,一般採用實現Runnable接口的方式編寫多線程代碼。

非線程安全:多個線程對同一個對象中的同一個實例變量進行操作時,會出現值被更改,值被同步的情況,進而影響程序的指向流程

jvm中 i - - 分三步執行,取得i值,計算i-1,對i進行復制。多個線程同時訪問,就會出現問題

1.3. currentThread()方法

返回代碼段正在被哪個線程調用的信息。

1.4. isAlive()方法

判斷當前線程是否處於活動狀態

線程處於正在運行,或者準備開始運行的階段,就認爲線程是存活測狀態。

currentThread 表示當前執行的線程,this表示當前的對象

1.5.sleep()方法

在指定的毫秒數內讓當前正在執行的線程 休眠。

1.6. getId()方法

取得線程的唯一標識

1.7. 停止線程

使用退出標誌,使線程征程退出,run執行完之後退出
使用stop強行停止線程, 不推薦這麼使用,stop,suspend及resume都是作廢過期的方法
使用interrupt方法中斷線程,interrupt只是給當前線程打了一個停止標誌,並不是真正的停止線程。

this.interrupted()測試當前線程是否已經是中斷狀態,執行後具有將狀態標誌清除爲false的功能。
this.isInterrupted()測試線程對象是否已經是中斷狀態,不清除狀態標誌。

線程中拋出異常也會停止線程。

在sleep狀態進入執行interrupt,會拋出,InterruptedException異常,反過來也是一樣的

可以使用interrupt和return結合來停止線程,不過建議使用拋異常的方式來實現線程的停止。異常可以上拋,使異常事件得以傳播。

1.8. 暫停線程

suspend和resume方法分別是暫停和恢復線程的運行,但是極易造成,公共的同步對象獨佔,其他線程無法訪問到這個對象,問題很多,建議不適用。

1.9 yield()方法

放棄當前的CPU資源。但是自己會進入就緒隊列,所以可能放棄之後又馬上佔有CPU資源

1.10. 線程的優先級

優先級越高的線程,就越容易得到CPU資源,但是具體由誰來執行還是由線程規劃器來確定執行的線程。使用setPrisetPriority()方法設置優先級,級別爲1-10

線程的優先級具有繼承性,執行線程默認和啓動線程具有相同的優先級
線程的優先級和代碼的執行順序無關,但是CPU儘量將執行資源讓給優先級比較高的線程。
線程優先級的特性:繼承性,規則性和隨機性

1.11. 守護線程

線程有兩種:用戶線程和守護線程
守護線程是一種特殊的線程,沒有非守護線程時,守護線程會自動銷燬。
垃圾回收機制就是典型的守護線程,使用setDaemon(true)就可以將線程設置爲守護線程。

2. 對象及變量的併發訪問

2.1. synchronized同步方法

方法內部的變量永遠是安全的,因爲作用域就在方法內
兩個線程訪問同一個對象的同步方法時,一定是線程安全的。
關鍵字synchronized取得的鎖都是對象鎖,而不是將一段代碼或者方法當做鎖

只有共享資源的讀寫訪問才需要同步化,如果不是共享資源,就不需要同步

鎖重入:synchronized具有鎖重入的功能,當一個線程獲取對象鎖之後,再次請求此對象鎖時是可以再次得到該對象的鎖的。存在子父類繼承關係時,子類完全可以通過可重入鎖調用父類的同步方法。

當一個線程執行的代碼出現異常時,其所持有的鎖會自動釋放。

同步不具體繼承性,子類方法無法繼承父類的synchronized關鍵字

2.2. synchronized同步語句塊

synchronized申明方法是有弊端的,只有當方法執行完畢之後纔會釋放對象鎖。使用同步塊的話可以這樣的問題。
當兩個併發線程訪問同一個對象的synchronized(this) 同步代碼塊時,一段時間內只有一個線程被執行,另一個線程必須等待當前線程執行完這個代碼執行完以後才能執行該該代碼。
當一個線程訪問objec的synchronized(this)同步代碼塊時,其他線程對同一個Object中其他所有的同步代碼塊的訪問都會被阻塞。
synchronized(非this對象)代碼塊的內容和同步方法是異步的。

synchronized關鍵字加到static 靜態方法上時,是給Class加鎖,加在非靜態方法時時給對象加鎖

死鎖:互相等待對方釋放鎖
如果同時持有相同的鎖,那麼這些線程就是同步的,如果分別獲取對象鎖,這些線程就是異步的。

2.3. volatile 關鍵字

主要作用是使變量在多個線程中可見。強制從公共堆棧中取得變量的值,而不是從私有數據棧中取得變得值。
volatile最致命的缺點就是不支持原子性。

原子操作是不能分割的整體,沒有其他線程能夠中斷或者檢查原子操作中的變量。使用AtomicInteger實現原子性

3. 線程間的通信。

3.1. 等待/通知 機制

通過while循環偵測某一個條件,缺點是浪費CPU資源

通過wait,notify 等待、通知機制實現線程的通信,wait的作用是使當前執行的線程進行等待。
在調用wait之前,線程必須獲得該對象的對象級別鎖,即只能在同步方法或同步快中調用wait方法,在執行wait方法之後,當前線程釋放鎖。
notify也要在同步方法或者同步方法塊中調用,在調用之前,線程也必須獲得該對象的對象級別鎖。
執行notify方法之後,當前線程也不會馬上釋放該鎖,呈wait狀態的線程也不會馬上獲得該對象鎖,需要等到notify線程將程序執行完畢。

notify可以隨機喚醒等待隊列中等待同一共享資源的一個線程,並使該線程進入等待狀態。notifyAll方法可以使所有的正在等待隊列中等待統一共享資源的的全部線程從等待狀態退出。

方法wait執行完之後,鎖會被自動釋放,但是notify方法被執行之後,鎖不會被釋放,而需要等待線程被執行完。wait(long)方法會在等待一定時間後自動喚醒,當然也可以notify喚醒

生產者消費者問題建議看書。

3.2.方法join的使用

等待線程對象銷燬執行。方法join具有使線程排隊運行的作用,有點類似同步的效果。

join(long)設置等待的時間。join(long)內部使用wait實現,所以會釋放鎖,sleep(long)卻不釋放鎖。

3.3 類ThreadLocal的使用

爲每個線程綁定自己的值。數據具有隔離性。

4. lock 的使用

 ReenTrantLock類的使用,在需要同步的代碼前使用lock.lock(),結束處使用lock.unlock()釋放鎖
關於這塊,建議看書。主要講等待/通知的另外一種實現方式。

5. 定時器timer Timer視屏

可以參考書籍和慕課網 
主要講解
    schedule(TimerTask task, Date time)
    schedule(TimerTask task, Date firstTime, long period)
    schedule(TimerTask task, long delay)
    schedule(TimerTask task, long delay, long period)
    scheduleAtFixedRate(TimerTask task, long delay, long period)

6. 單例模式和多線程

主要講解 單例模式在多線程中的安全性

7. 拾遺增補

7.1. 線程的狀態

NEW 至今尚未啓動的
RUNNABLE 正在java虛擬機中執行的線程
BLOCKED    受阻塞並等待某個監控器鎖的線程
WAITTING    無限期的等待另一個線程來執行某一個特定操作的線程
TIME_WAITING    等待一個線程執行取決於指定等待時間
TERMINATED        已退出的線程

7.2 線程租

可以將線程歸屬到某一個線程組中,線程組中可以擁有線程對象,也可以擁有線程組,組中還可以有線程。
線程組可以批量管理線程或者線程組對象,有效的對線程或線程組對象進行組織。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章