關於線程的那些事兒

其實線程只有"就緒"、"阻塞"、"運行"三種狀態:
1. 運行狀態,線程正在幹活的狀態
2. 就緒狀態,CPU正在忙活別的,線程搖晃着一個"恭候您光臨"的小旗子的狀態

3. 阻塞狀態,線程主動讓出CPU資源

"新建"和"終止"這兩種狀態其實並不是線程的狀態,而是java.lang.Thread對象的狀態。可以說,處於"新建"和"終止"狀態的"線程"其實並不是線程,而只是一個代表着線程對象而已。

所以我們把"新建(NEW)"和"終止(TERMINATED)"兩種狀態去掉,那麼Java定義的線程狀態還有4種:
1. RUNNABLE
2. BLOCKED
3. WAITING
4. TIMED_WAITING

這四種狀態怎麼對應到"就緒"、"阻塞"、"運行"這三種狀態裏呢:
1. RUNNABLE,對應"就緒"和"運行"兩種狀態,也就是說處於就緒和運行狀態的線程在java.lang.Thread中都表現爲"RUNNABLE"
2. BLOCKED,對應"阻塞"狀態,此線程需要獲得某個鎖才能繼續執行,而這個鎖目前被其他線程持有,所以進入了被動的等待狀態,直到搶到了那個鎖,纔會再次進入"就緒"狀態
3. WAITING,對應"阻塞"狀態,代表此線程正處於無限期的主動等待中,直到有人喚醒它,它纔會再次進入就緒狀態
4. TIMED_WAITING,對應"阻塞"狀態,代表此線程正處於有限期的主動等待中,要麼有人喚醒它,要麼等待夠了一定時間之後,纔會再次進入就緒狀態



1.當線程調用了自身的sleep()方法或其他線程的join()方法,進程讓出CPU,然後就會進入阻塞狀態,該狀態既停止當前線程,但並不釋放所佔有的資源(不會釋放鎖)


2.線程調用了yield()方法,意思是放棄當前獲得的CPU時間片,回到就緒狀態,這時與其他進程處於同等競爭狀態,OS有可能會接着又讓這個進程進入運行狀態


3.suspend() 和 resume()方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態,並且不會自動恢復,必須其對應的resume()被調用,才能使得線程重新進入可執行狀態


4.wait()和 notify() 方法:當線程調用wait()方法後會進入等待隊列(進入這個狀態會釋放所佔有的所有資源,與阻塞狀態不同),進入這個狀態後,是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒

注:
前面敘述的所有方法都可在任何位置調用,但是wait() 和 notify() 方法這一對方法卻必須在 synchronized 方法或塊中調用,理由也很簡單,只有在synchronized方法或塊中當前線程才佔有鎖,纔有鎖可以釋放

當線程剛進入可運行狀態(注意,還沒運行),發現將要調用的資源被synchroniza(同步),獲取不到鎖標記,將會立即進入鎖池狀態,等待獲取鎖標記(這時的鎖池裏也許已經有了其他線程在等待獲取鎖標記,這時它們處於隊列狀態,既先到先得),一旦線程獲得鎖標記後,就轉入就緒狀態,等待OS分配CPU時間片;


不釋放鎖

  • 線程執行同步代碼塊或同步方法時,程序調用Thread.sleep(Long l)、Thread.yield()方法暫停當前線程的執行
  • 線程執行同步代碼塊時,其它線程調用該線程suspend()方法將該線程掛起,該線程不會釋放鎖(同步監視器)
  • 儘量避免使用suspend()和resume()來控制線程

釋放鎖

  • 當前線程的同步方法、同步代碼塊執行結束
  • 當前線程的同步方法、同步代碼塊遇到break、return終止該代碼塊、該方法的繼續執行
  • 當前線程的同步方法、同步代碼塊中出現了未處理Error和Exception,導致異常結束
  • 當前線程在同步方法、同步代碼塊中執行了線程對象的wait()方法,當前線程暫停,並釋放鎖