1. 程式人生 > 實用技巧 >多執行緒02

多執行緒02

執行緒的幾種狀態

執行緒狀態概述

當執行緒被建立並啟動之後,它既不是一啟動就進入到了執行狀態,也不是一直處於執行狀態,線上程的宣告週期中有6中狀態,在java的API幫助文件中java.util.Thread.State這個列舉給出了執行緒的6種狀態.

執行緒狀態導致狀態發生條件
NEW(新建) 執行緒剛被建立,但是還沒有啟動,還沒有呼叫start方法
Runnable(可執行) 執行緒可以在java虛擬器中執行的狀態,可以是正在執行自己的程式碼,也可能沒有執行,這取決於處理器
Blocked(鎖阻塞) 當一個執行緒試圖獲取一個物件鎖,而物件鎖被其他執行緒所持有,則該執行緒進入到Blocked(鎖阻塞狀態),當該執行緒持有鎖時,該執行緒就進入到Runnable狀態.
WAITING(無線等待) 一個執行緒在等待另一個執行緒執行一個動作(新建時),該執行緒進入到Wating狀態,進入這個Wating狀態後,是不能自動喚醒的,必須等待另一個執行緒呼叫notify或者notifyAll方法才能喚醒
TIMED_WAITING(計時等待) 同Wating狀態,有幾個方法有超時引數,呼叫他們將進入Timed Wating狀態,這一狀態將一直保持到超時期滿或者是收到喚醒通知,帶有超時引數的常用方法有Thread.sleep().Object.wait().
TERMNATED(被終止) 因為run方法正常退出而死亡,或者因為沒有捕獲的異常終止了run方法而死亡.

六種狀態切換原理:

New 新建狀態: 需要Therad或者Runable的實現 需要等待start方法開啟

RUNNABLE:可執行狀態 :被start呼叫的新建執行緒

Blocked阻塞狀態:多個執行緒之間互相爭奪cpu的使用權的執行時間,得到或者釋放了執行緒切換到其他執行緒,那麼這個執行緒就會在可執行狀態和阻塞狀態來回切換,擁有cpu的執行資格,等待cpu空閒時執行

TIMED_WAITING休眠計時等待狀態 方法中被sleep(long)或者wait(long)設定執行緒會被休眠狀態,等待計時結束自動喚醒或者被主動喚醒進入執行狀態,休眠狀態:放棄了cpu的執行資格,cpu空閒也不執行

WAITNG無限(永久等待狀態) Obect.wait()計時喚醒方法 Object.notify()喚醒執行緒方法 此狀態只有被喚醒才能進入執行狀態

TERMINATED 死亡狀態 run方法結束 或者使用stop() 執行緒被終止.

備註:

  • 休眠計時等待狀態和永久等待狀態也被稱為凍結狀態

  • 無限等待狀態和 TIMED_WAITING計時等待狀態被喚醒但是沒有拿到鎖,依然會進入阻塞狀態.

Timed Wating(計時等待)

Timed Wating在javaAPI中描述為:一個正在限時等待另一個執行緒執行一個(喚醒)動作的執行緒處於這一狀態

其實當我們呼叫了sleep方法之後,當前正在執行的執行緒就進入到了計時等待狀態.

public void sleep(long a): 執行緒暫停方法

練習: 實現一個計時器,計數到100,在每個數字之間暫停一秒,每擱10個數組輸出一個字串

public class MyThread extends Thread{
Override
public void run(){
for(int i=1;i<100;i++){
if(i/10==0){
System.out.println("==============================");
}
System.out.println(i);
//在每個數字之間我要暫停一秒
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStachTrace();
}
}
}
//準備一個main函式
public static void main(String [] args){
new MyThread().start();
}
}

備註:

1.進入到Timed Waiting狀態的一種常見的操作是呼叫sleep方法,單獨的執行緒也可以呼叫,不一定非要有協作關係

2.為了讓其他執行緒有機會執行到,一般建議將Thread.sleep呼叫放到執行緒run方法內,這樣才能保證該執行緒執行過程中會睡眠.

3.sleep與鎖無關,執行緒睡眠到期會自動甦醒,並返回到Runnable狀態.sleep裡面的引數指定的時間是執行緒不會執行的最短時間.,因此sleep()方法不能保證該執行緒睡眠到期後就會立刻開始執行,

Blocked鎖阻塞狀態

blocked狀態在javaAPI中描述為:一個正在阻塞等待一個監視器鎖(鎖物件)的執行緒處於這一狀態.

比如:執行緒A與執行緒B程式碼中使用了同一把鎖,如果執行緒A獲取到了鎖物件,執行緒A就進入Runnable狀態,反之執行緒B就進入了Blocked鎖阻塞狀態.

Waiting 無限等待狀態

waiting狀態在JavaAPI中的描述為:一個正在無線等待另一個執行緒執行一個特別的(喚醒)動作的執行緒處於這一狀態.

一個呼叫了某個物件的Object,wait()方法的執行緒,會等待另一個執行緒呼叫此物件Objectnotify()或者Object.notifyAll()方法

其實waiting狀態並不是一個執行緒的操作,它體現的是多個執行緒之間的通訊*.可以理解為東哥執行緒之間的協作關係,多個執行緒會爭取鎖,同時相互之間有存在協作關係

等待喚醒機制

執行緒間通訊

概念:多個執行緒在處理同一資源,但是處理的動作(執行緒的任務)卻又不相同.

比如說,執行緒A用來生存一個娃哈哈,執行緒B用來消費娃哈哈飲料.娃哈哈飲料可以理解為同一資源,執行緒A與執行緒B處理的動作,一個是生產,一個是消費.那麼執行緒A與執行緒B之間就存線上程通訊問題.

為什麼要處理執行緒之間的通訊:

多個執行緒併發在執行時,在預設情況下CPU隨機切換執行緒的,當我們需要多個執行緒共同來完成一件任務時,並且我們希望他們有規律的執行,那麼多執行緒之間就需要一些協調通訊,以此類幫助我們達到多執行緒共同操作一份資料.

如何保證執行緒之間有效利用資源:

多個執行緒在處理同一個資源的時候,並且任務還不相同,需要執行緒通訊來幫助我們解決執行緒之間對同一變數的操作

就是多個執行緒在操作同一份資料時,為了避免對同一共享變數的爭奪,也就是我們需要通過一定的邏輯來使各個執行緒有效的利用資源.而這些邏輯 就是利用等待喚醒機制(wait()和notify())

等待喚醒機制

這是多個執行緒之間的一種協作機制.

就是一個執行緒進行了規定操作後,就進入了等待操作.(wait()),等待其他執行緒執行完他們的指定程式碼後,再將其喚醒(notify);

在有多個執行緒進行等待時,如果需要喚醒所有執行緒,可以使用notifyAll()來喚醒所有的等待執行緒

wait//notify就是執行緒間的一種協作機制.

等待喚醒中的方法:

等待喚醒機制就是用來解決執行緒間通訊問題的.可以使用到的方法有三個如下:

  • wait():執行緒不再活動,不再參與CPU的排程,進入到wait set中,因此不會浪費CPU資源,也不會去競爭鎖,這時的執行緒的執行緒狀態就是WAITING狀態.他還要等著別的執行緒執行一個特別的動作,就是喚醒通知(notify)在這個物件上等待的執行緒從wait set中釋放出來,重新進入到排程佇列(ready queue)中.

  • notify():選取所通知物件的 wait set中的一個執行緒釋放.例如:餐廳有空位置後,等候就餐最久的顧客最先入座.

  • notifyAII():釋放所通知物件的wait set中的正在等待的全部執行緒.

備註:

哪怕只是通知了一格等待執行緒,被通知的執行緒也不會立即恢復執行,因為他當初中斷的地方是在同步塊內,而此刻他已經不持有鎖了,所以他需要再次嘗試著去獲取鎖(很可能面臨著其他執行緒的競爭),成功後才能當初呼叫wait方法之後的地方恢復執行.總結下:

如果能獲取到鎖,執行緒就從WAITING狀態轉變成RUNNABLE狀態

否則從,wait set 中,又進入set中,執行緒就從WAITING狀態轉變成BLOCKED狀態.

呼叫wait和notify的注意細節:

1.wait方法與notify方法必須有同一個鎖物件.因為對應的鎖物件才能通過notify喚醒使用同一個鎖物件呼叫的wait方法後的執行緒.

2.wait方法與notify方法時屬於Object類的方法的,因為鎖物件可以是任意物件.因為鎖物件可以是任意物件,而任意物件的所屬類都是繼承了Object類

3.wait方法與motify方法必須要在同步程式碼塊或者同步方法中使用..因為,必須通過鎖物件呼叫這兩個方法來實現等待與喚醒.

生產者與消費者問題

等待喚醒機制案例:

舉一個例子:生產包子與消費包子

包子鋪執行緒生產包子,吃貨執行緒消費包子.當沒有包子的時候(包子的狀態位false),吃貨執行緒需要等待,包子鋪執行緒生產包子(包子的狀態為true),並通知吃貨執行緒(接觸吃貨等待的狀態),因為已經有了包子,那麼包子鋪執行緒就需要進入到等待狀態
接下來,吃貨執行緒能夠記你一步執行則取決於鎖的獲取情況,如果吃貨執行緒獲取到鎖,那麼就執行吃包子的動作,包子吃完了(包子的狀態位false),需要通知包子鋪執行緒(接觸包子鋪執行緒等待狀態),此時吃貨執行緒就進入到等待狀態.包子鋪執行緒能否進一步執行則取決於鎖的獲取情況.