文章目錄
一、名詞概念
1.1 串行和併發
串行: 多個任務依次按順序執行。
併發: 多個任務同時執行。
1.2 進程和線程
進程:
簡單來說就是對 一個程序運行所佔用的各種資源 的描述。
進程之間資源 不共享 。
線程:
一個進程中任務執行的最小單元,一個進程中 至少有一個 線程。
線程之間資源 可以共享 ,被多個線程共享的資源叫 臨界資源。
二、線程的生命週期
一個線程從實例化完成到銷燬的過程,叫做線程的 生命週期 。
一個線程的生命週期擁有 新生,就緒,運行,阻塞 ,死亡 這幾個狀態。
狀態 | 解釋 |
---|---|
新生態 | 線程對象被實例化,單還沒有做任何操作 |
就緒態 | 線程被開啓,開始爭奪CPU資源 |
運行態 | 線程搶到CPU時間片,開始執行該線程的邏輯 |
阻塞態 | 一個線程在運行過程中,由於某些操作,放棄CPU時間片, 並且不再參與CPU資源競爭,此時線程處於掛起狀態 |
死亡態 | 一個線程對象被銷燬 |
三、線程的創建
3.1 線程的創建方式
1. 繼承Thread類
2.實現Runnable接口
3.2 start()和run()方法
相同:
都能執行線程內的邏輯。
不同:
start()方法會讓線程進入就緒狀態,而run()不會。
調用start()方法,邏輯將在子線程執行,run()則會在當前線程執行。
四、線程的常用方法
4.1 線程的命名
1.通過setName()方法
2.通過Thread類的構造方法
4.2 線程的休眠
使用 sleep() 方法,休眠時間單位爲 毫秒,使線程由 運行狀態 進入 阻塞狀態。
休眠時間結束後重新進入就緒狀態。
4.3 線程的優先級
對線程搶到CPU時間片的 概率 的描述。
通過 setPriority() 方法,設置線程的優先級。參數取值爲[0,10]的 整數 。
優先級越高,搶到CPU時間片的概率就越高;優先級越,低搶到的CPU時間片的概率就越低。
4.4 線程的禮讓
使用 yield() 方法,使當前的線程釋放佔用的CPU資源,進入 就緒狀態 。
五、臨界資源問題
定義:
在併發編程中對臨界資源的處理不當, 導致數據不一致的問題。
原因:
一個線程將臨界資源置於中間狀態後, 另一個線程訪問了這個中間狀態並基於此中間狀態做了進一步的處理。
解決辦法:
使用 線程鎖 來防止多個線程訪問同一個臨界資源。
六、鎖
6.1 同步鎖(synchronize)
同步代碼塊:
運行狀態的線程進入 synchronize 同步代碼塊會爲臨界資源上鎖,而其他線程在碰到鎖標記時會進入 鎖池 。
鎖池內的線程爭搶鎖標記以進入就緒狀態,臨界資源解鎖後,搶到鎖標記的線程將進入同步代碼塊繼續運行。
synchronize的括號中可以是 對象 也可以是 類 ,但是要確保每一個線程看到的是同一把鎖,以下這種寫法是不起作用的:
同步方法:
使用 synchronize 關鍵字修飾方法。
- 如果修飾的是靜態方法,那麼該鎖爲 當前類 的類鎖;
- 如果修飾的是非靜態方法,則爲 this 對象鎖。
6.2 顯示鎖
使用 ReentrantLock 創建鎖對象。 lock() 和 unlock() 分別用於上鎖和解鎖臨界資源。
6.3 死鎖
定義: 多個線程持有對方所需要的鎖對象,而又不釋放自己的鎖。
死鎖條件:
① 互斥條件:一個資源每次只能被一個進程使用,即在一段時間內某 資源僅爲一個進程所佔有。此時若有其他進程請求該資源,則請求進程只能等待;
② 請求與保持條件:進程已經保持了至少一個資源,但又提出了新的資源請求,而該資源 已被其他進程佔有,此時請求進程被阻塞,但對自己已獲得的資源保持不放;
③ 不可剝奪條件:進程所獲得的資源在未使用完畢之前,不能被其他進程強行奪走,即只能 由獲得該資源的進程自己來釋放(只能是主動釋放);
④ 循環等待條件:若干進程間形成首尾相接循環等待資源的關係。
這四個條件是死鎖的必要條件,
只要系統發生死鎖,這些條件必然成立;
而只要上述條件之一不滿足,就不會發生死鎖。
解決方法:
wait() 方法:是Object類中的一個方法,使當前線程釋放自己的鎖標記,並讓出CPU資源,進入等待隊列。
notify() 方法:是Object類中的一個方法,喚醒等待隊列中的一個等待對應鎖標記的線程,使得這個線程進入鎖池。
notifyAll() 方法:是Object類中的一個方法,喚醒等待隊列的等待對應鎖標記的所有線程,使它們進入鎖池。