JUC_AQS_概念最最基礎入門(高手莫進)

JUC是JAVA推出頂替synchronize的jar包

JUC : java.util.concurrent 也就是java併發工具包
裏面含有線程池, 阻塞隊列,同步器,計時器等組件 etc…

OK 以上關於JUC 的定位已經瞭解了,那麼既然JUC 想要代替synchronize關鍵字,那麼關鍵 就在與 lock(鎖)

然而既然實現鎖,那麼有兩點肯定是避不開的

1) 線程如何爭搶鎖?

2) 線程爭搶鎖失敗以後,該如何處理?



1) 線程如何爭搶鎖?
鎖 一般有兩個特性可以被稱之爲鎖:
1) 共享性
2) 排他性
所以在爭搶鎖的時候,那麼這個鎖一定在在多個線程中共享的, 我們所要做的就是如何保證它在爭搶鎖時的一個安全性.

在java中有一種實現方式被稱之爲CAS 使用的是 樂觀鎖的理念

所謂的樂觀鎖 以java的實現如下:

入參: 對象, 內存值, 預期值, 更新值
其中 對象即爲被多個線程共享的鎖對象
內存值 就是鎖狀態在內存中存在的位置
假設當前 鎖狀態的含義爲:
	0 代表鎖是沒有被佔用
	1 代表當前鎖已被佔用
那麼在樂觀鎖中 預期值就是 0 ,更新值就是 1
判斷邏輯:
	1) 使用預期值 與 內存中的鎖狀態做對比
	2) 如果返回true代表當前鎖沒有被佔用, 
		即修改成 參數中的更新值
	3) 如果返回false就算作爭搶失敗
(ps: java中的CAS最後的調用的是 native中的本地函數實現的
	在此不做展開)

2) 線程爭搶鎖失敗以後,該如何處理?

在線程爭搶鎖失敗之後, 總不能不管線程,讓其跳過當前代碼塊,走下面的流程.

因此我們需要一個線程管理者,

在JUC裏面這個管理者 被稱之爲AQS.

其實現方式爲雙向鏈表,

AQS的工作邏輯如下:

1) 當ThreadA 與ThreadB 互相爭搶鎖

2) ThreadA爭搶鎖成功,將其作爲AQS head節點

3) 將其放入AQS隊列,在放入AQS隊列之前搶一次鎖

4) ThreadB 爭搶鎖失敗,在只有兩個線程的情況下 ThreadB 是作爲 ThreadA 的next 存貯在AQS隊列中

5) 對ThreadB 的node節點 使用自旋,死循環搶鎖

6) 短暫時間片之後,如果沒有搶到鎖將調用 park函數將線程掛起

7) 當ThreadA 執行完畢釋放鎖之後,喚醒 next 節點 ,
在這裏也就是 ThreadB節點

8) ThreadB節點進行鎖的爭搶,如果搶奪成功 則將 
ThreadB節點設置爲AQS隊列的head 節點 
(ps: 誰搶奪鎖成功誰就是 AQS隊列中的head節點)

由以上粗略的工作邏輯我們可以大致瞭解下 AQS是如何工作的, 也瞭解了在JUC之中 如果線程搶不到鎖, 是被如何分配的


題外話:

在java中 實現lock接口的有 ReentrantLock

實現依賴AQS隊列的有 FairSync(公平鎖) 與 NonfairSync(非公平鎖)
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章