1. 程式人生 > >Java多執行緒學習記錄

Java多執行緒學習記錄

java多執行緒
1 執行緒模型
1.1執行緒優先順序
   ·執行緒自願地放棄控制:執行緒顯式地放棄控制權、休眠或在I/O之前阻塞,都會
   出現這種情況。在這種情況下,檢查所有其他執行緒,並且準備執行的執行緒中
   優先順序最高的那個執行緒會獲得資源。
   ·執行緒被優先順序更高的執行緒取代。對於這種情況,沒有放棄控制權的低優先順序
   執行緒不管正在做什麼,都會被高優先順序執行緒簡單地取代。基本上,只要高優
   先級執行緒希望執行,他就會取代低優先順序執行緒,這稱為搶佔式多工處理。


如果具有相同優先順序的兩個執行緒競爭cpu資源,這種情況有些複雜。對於windows這
類作業系統,優先順序相等的執行緒以迴圈方式自動獲得cpu資源。對於其他型別的操
作系統,優先順序相等的執行緒以迴圈方式自動獲得cpu資源。對於其他型別的作業系統,
優先順序相等的執行緒必須自願的向其他執行緒放棄控制權,否則其他執行緒就不能執行。


警告:作業系統以不同的方式對具有相等優先順序的執行緒進行上下文切換,可能會
引起可以執行問題。


1.2 同步
1.3 訊息傳遞
    java的訊息傳遞系統允許某個執行緒進入物件的同步方法,然後進行等待,直到
    其他執行緒顯式地通知這個執行緒退出為止。
1.4 Thread類和Runnable介面
    Java的多執行緒系統是基於Thread類、Thread類的方法及其伴隨介面Runnable而構建
    的。
    Thread類封裝了執行緒的執行。因為不能直接引用正在執行的執行緒的細微狀態,
    所以需要通過代理進行處理,Thread例項就是執行緒的代理。
    為了建立新執行緒,程式可以擴充套件Thread類或實現Runnable介面。
    
    Thread類定義的一些方法:
getName() 獲取執行緒的名稱
getPriority() 獲取執行緒的優先順序
isAlive() 確定執行緒是否仍然在執行
join() 等待執行緒終止
run() 執行緒的入口點
sleep() 掛起執行緒一段時間
start() 通過呼叫執行緒的run()方法啟動執行緒


2 主執行緒
·其他子執行緒都是從主執行緒產生的。
·通常,主執行緒必須是最後才結束執行的執行緒,因為它要執行各種關閉動作。
儘管主執行緒是在程式啟動時自動建立的,但是可以通過Thread物件對其進行控制。
為此,必須呼叫currentThread()方法獲取對主執行緒的一個引用。該方法是Thread類
的共有靜態成員,它的一般形式如下所示:
static Thread currentThread()
該方法返回對呼叫它的執行緒的引用。一旦得到對主執行緒的引用,就可以像
控制其他執行緒那樣控制主執行緒了。
PS:主執行緒的優先順序預設值:5,執行緒組:java.lang.ThreadGroup[name=main,maxpri=10]


3 建立執行緒
最通常情況下,通過例項化Thread型別的物件建立執行緒。
建立執行緒的 兩種方法:
·實現Runnable介面
·擴充套件Thread類本身


3.1 實現Runnable介面(方式一)
    run方法和main執行緒的唯一區別:run()方法為程式中另外一個併發執行緒的執行建立了入口點。
當run()方法返回時,這個執行緒將結束。
    在建立實現了Runnable介面的類之後,可以在類中例項化Thread型別的物件。
Thread的建構函式之一:Thread(Runnable threadOb,String threadName)
    其中threadOb是實現了Runnable介面的類的例項,這定義了從何處開始執行執行緒。
新執行緒的名字由threadName指定。
    在建立了新執行緒之後,只有呼叫執行緒的start()方法,執行緒才會執行,該方法是在Thread
類中宣告的。本質上,start()方法執行對run()方法的呼叫。
3.2 擴充套件Thread類(方式二)
    建立一個擴充套件了Thread的新類,然後建立該類的例項。擴充套件類必須重寫run()方法,run()方法
是新執行緒的入口點。擴充套件類還必須呼叫start()方法以開始新執行緒的執行。


4.建立多個執行緒


5.使用isAlive()和join()方法
有兩種方法可以確定執行緒是否已經結束。首先,可以為執行緒呼叫isAlive()方法。該方法由Thread類定義。
final boolean isAlive()
如果執行緒仍然在執行,isAlive()方法就返回true,否則返回false.
·join()方法用來等待執行緒結束,如下所示:
final void join() throws InterruptedException
該方法會一直等待,直到呼叫執行緒終止。
命名原因:呼叫執行緒一直等待,直到指定的執行緒加入(join)其中為止。
join()方法的另外一種形式,允許指定希望等待指定執行緒終止的最長時間。


6.執行緒優先順序
設定執行緒優先順序,使用setPriority()方法,它是Thread類的成員。該方法的
一般形式: final void setPriority(int level).
其中level是優先順序,取值在MIN_PRIORITY和MAX_PRIORITY之間。目前1<=level<=10.預設優先順序NORM_PRIORITY是5.
這些優先順序在Thread類中作為static final變數定義。
final int getPriority()//獲取當前設定的優先順序。
警告:不同的Java實現對於任務排程可能有很大的區別。如果執行緒依賴於搶佔式行為,而不是協作性地放棄CPU,
那麼經常會引起不一致性。使用Java實現可預測、跨平臺行為地最安全方法是使用自願放棄CPU控制權地執行緒。


7.同步
同步地關鍵是監視器的概念,監視器是用作互斥鎖的物件。在給定時刻,只有一個執行緒可以擁有監視器。
當執行緒取得鎖時,也就是進入了監視器。其他所有企圖進入加鎖監視器的執行緒都會被掛起,直到第一個執行緒推出監視器。
也就是說,這些等待的其他執行緒在等待監視器。如果需要的話,擁有監視器的執行緒可以再次進入監視器。


同步程式碼的方法(使用synchronized,兩種)


7.1使用同步方法
Java中,所有物件都有與他們自身關聯的隱式監視器。
為了進入物件的監視器,只需要呼叫使用synchronized關鍵字修飾過的方法。
當某個執行緒進入同步方法中時,條用同一例項的該同步方法(或其他同步方法)的所有其他執行緒都必須等待。
為了推出監視器並將物件的控制權交給下一個等待執行緒,監視器的擁有者只需要簡單地從同步方法返回。


記住!!!:一旦執行緒進入一個例項地同步方法,所有其他執行緒就都不能再進入相同例項地任何同步方法。但是,
仍然可以繼續呼叫同一例項地非同步部分。


7.2 synchronized語句
將類定義的方法的呼叫放到synchronized程式碼塊中。一般形式如下:
synchronized(objRef){
//statements to be synchronized
}
其中,objRef是對被同步物件的引用。synchronized程式碼塊確保對objRef物件的成員方法的呼叫,只會在
當前執行緒成功進入objRef的監視器之後發生。


8 執行緒間通訊
Java通過wait()、notify()以及notifyAll()方法,提供了一種巧妙的執行緒間通訊機制,
這些方法再Object中是作為final方法實現的,因此所有類都有這些方法。所有這3個
方法都只能在同步上下文中呼叫。
·wait()方法通知呼叫執行緒放棄監視並進入休眠,直到其他一些執行緒進入同一個監視器並呼叫notify()方法或nitifyAll()方法。
·notify()方法喚醒呼叫相同物件的wait()的執行緒。
·notifyAll()方法喚醒呼叫相同物件的wait()方法的所有執行緒,其中的一個執行緒將得到訪問權。
這3個方法都是在Object類中定義的:
final void wait() throws InterruptedException
final void notify()
final void notifyAll()
wait()方法還有另外一種形式,允許指定等待的時間間隔。
    在通過例子演示執行緒間通訊之前,還有重要的一點需要指出。儘管在正常情況下,wait()方法會等待直到呼叫notify()或notifyAll()方法,
但是還有一種機率很小確很可能會發生的情況,等待執行緒由於假喚醒(spurious wakeup)而被喚醒。對於這種情況,等待執行緒也會被喚醒,然而
卻沒有呼叫notify()或notifyAll()方法(本質上,執行緒在沒有什麼明顯理由的情況下就被恢復了)。由於存在這種極小的可能,Oracle推薦應當
在一個檢查執行緒等待條件的迴圈中呼叫wait()方法。


死鎖


9 掛起、恢復、停止執行緒
10 獲取執行緒的狀態
Thread.State getState()
該方法返回Thread.State型別的值。State是由Thread類定義的列舉型別
getState()方法的返回值
BLOCKED:執行緒因為正在等待需要的鎖而掛起執行
NEW:執行緒還沒有開始執行
RUNNABLE:執行緒要麼當前正在執行,要麼在獲得CPU的訪問權之後執行
TERMINATED:執行緒已經完成執行
TIMED_WAITING:執行緒掛起執行一段指定的時間,例如當呼叫sleep()方法的時候就會處於這種狀態。當呼叫wait()或join()方法的
暫停版時,也會進入這種狀態
WAITING:執行緒因為等待某些動作而掛起執行。例如,因為呼叫非暫停版的wait()或join()方法而等待時,會處於這種狀態。


11 使用多執行緒
有效利用Java多執行緒特性的關鍵時併發地而不是順序地思考問題
Fork/Join框架