Thread详解
具體可參考:Java并發(fā)編程:Thread類的使用,這里對線程狀態(tài)的轉(zhuǎn)換及主要函數(shù)做一下補充。
一. 線程狀態(tài)轉(zhuǎn)換圖
注意:
1.1 阻塞與等待的區(qū)別
阻塞:當一個線程試圖獲取對象鎖(非java.util.concurrent庫中的鎖,即synchronized),而該鎖被其他線程持有,則該線程進入阻塞狀態(tài)。它的特點是使用簡單,由JVM調(diào)度器來決定喚醒自己,而不需要由另一個線程來顯式喚醒自己,不響應中斷。
等待:當一個線程等待另一個線程通知調(diào)度器一個條件時,該線程進入等待狀態(tài)。它的特點是需要等待另一個線程顯式地喚醒自己,實現(xiàn)靈活,語義更豐富,可響應中斷。例如調(diào)用:Object.wait()、Thread.join()以及等待Lock或Condition。
需要強調(diào)的是雖然synchronized和JUC里的Lock都實現(xiàn)鎖的功能,但線程進入的狀態(tài)是不一樣的。synchronized會讓線程進入阻塞態(tài),而JUC里的Lock是用LockSupport.park()/unpark()來實現(xiàn)阻塞/喚醒的,會讓線程進入等待態(tài)。但話又說回來,雖然等鎖時進入的狀態(tài)不一樣,但被喚醒后又都進入runnable態(tài),從行為效果來看又是一樣的。
二. 主要操作?
2.1 start()
新啟一個線程執(zhí)行其run()方法,一個線程只能start一次。主要是通過調(diào)用native start0()來實現(xiàn)。
1 public synchronized void start() { 2 //判斷是否首次啟動 3 if (threadStatus != 0) 4 throw new IllegalThreadStateException(); 5 6 group.add(this); 7 8 boolean started = false; 9 try { 10 //啟動線程 11 start0(); 12 started = true; 13 } finally { 14 try { 15 if (!started) { 16 group.threadStartFailed(this); 17 } 18 } catch (Throwable ignore) { 19 /* do nothing. If start0 threw a Throwable then 20 it will be passed up the call stack */ 21 } 22 } 23 } 24 25 private native void start0();2.2 run()
run()方法是不需要用戶來調(diào)用的,當通過start方法啟動一個線程之后,當該線程獲得了CPU執(zhí)行時間,便進入run方法體去執(zhí)行具體的任務。注意,繼承Thread類必須重寫run方法,在run方法中定義具體要執(zhí)行的任務。
2.3 sleep()
sleep方法有兩個重載版本:
1 sleep(long millis) //參數(shù)為毫秒 2 3 sleep(long millis,int nanoseconds) //第一參數(shù)為毫秒,第二個參數(shù)為納秒sleep相當于讓線程睡眠,交出CPU,讓CPU去執(zhí)行其他的任務。
但是有一點要非常注意,sleep方法不會釋放鎖,也就是說如果當前線程持有對某個對象的鎖,則即使調(diào)用sleep方法,其他線程也無法訪問這個對象。
2.4 yield()
調(diào)用yield方法會讓當前線程交出CPU權(quán)限,讓CPU去執(zhí)行其他的線程。它跟sleep方法類似,同樣不會釋放鎖。但是yield不能控制具體的交出CPU的時間,另外,yield方法只能讓擁有相同優(yōu)先級的線程有獲取CPU執(zhí)行時間的機會。
注意,調(diào)用yield方法并不會讓線程進入阻塞狀態(tài),而是讓線程重回就緒狀態(tài),它只需要等待重新獲取CPU執(zhí)行時間,這一點是和sleep方法不一樣的。
2.5 join()
join方法有三個重載版本:
1 join() 2 join(long millis) //參數(shù)為毫秒 3 join(long millis,int nanoseconds) //第一參數(shù)為毫秒,第二個參數(shù)為納秒join()實際是利用了wait(),只不過它不用等待notify()/notifyAll(),且不受其影響。它結(jié)束的條件是:1)等待時間到;2)目標線程已經(jīng)run完(通過isAlive()來判斷)。
1 public final synchronized void join(long millis) throws InterruptedException { 2 long base = System.currentTimeMillis(); 3 long now = 0; 4 5 if (millis < 0) { 6 throw new IllegalArgumentException("timeout value is negative"); 7 } 8 9 //0則需要一直等到目標線程run完 10 if (millis == 0) { 11 while (isAlive()) { 12 wait(0); 13 } 14 } else { 15 //如果目標線程未run完且阻塞時間未到,那么調(diào)用線程會一直等待。 16 while (isAlive()) { 17 long delay = millis - now; 18 if (delay <= 0) { 19 break; 20 } 21 wait(delay); 22 now = System.currentTimeMillis() - base; 23 } 24 } 25 }2.6 interrupt()
此操作會將線程的中斷標志位置位。如果線程sleep()處于timed_waiting狀態(tài),則還會拋出InterruptException;如果線程在運行態(tài)則不會受此影響。
可以通過以下三種方式來判斷中斷:
1)isInterrupted()
此方法只會讀取線程的中斷標志位,并不會重置。
2)interrupted()
此方法讀取線程的中斷標志位,并會重置。
3)throw InterruptException
拋出該異常的同時,會重置中斷標志位。
2.7 suspend()/resume()
掛起線程,直到被resume,才會蘇醒。
但調(diào)用suspend()的線程和調(diào)用resume()的線程,可能會因為爭鎖的問題而發(fā)生死鎖,所以JDK 7開始已經(jīng)不推薦使用了。
?
轉(zhuǎn)載于:https://www.cnblogs.com/waterystone/p/4920007.html
總結(jié)
- 上一篇: PropertyGrid控件 分类(Ca
- 下一篇: LeetCode(53):Maximum