死神--->一番隊(duì)隊(duì)長(zhǎng)山本元柳齋重國(guó)
目錄:
- 1贡蓖、Lock介紹
- 2、Lock的實(shí)現(xiàn)類ReentrantLock
- 3煌茬、AQS簡(jiǎn)介
- 4斥铺、ReentrantLock類體系
- 5 、Lock使用
- 6坛善、AQS原理:
- 6.1晾蜘、AQS內(nèi)存模型
- 6.2、AQS類體系
- 6.3浑吟、AQS模板方法
- 6.4笙纤、Node節(jié)點(diǎn)
- 6.5、CHL同步隊(duì)列
- 6.6组力、同步狀態(tài)獲仁∪荨(acquire)與釋放(release)
- 6.7、線程阻塞與喚醒
- 7燎字、AQS-產(chǎn)品之一ReentrantLock
- 7.1腥椒、圖解:獲取鎖阿宅、釋放鎖、入同步隊(duì)列
- 7.2笼蛛、公平鎖&非公平鎖
- 8洒放、面試常見問題
- 1、公平鎖(FairSync)和非公平鎖(NonfairSync)的區(qū)別滨砍?
- 2往湿、ReentrantLock如何處理線程中斷的?
- 3、未完待續(xù)~
1惋戏、Lock介紹
Lock 接口實(shí)現(xiàn)類提供了比使用 synchronized 方法和語(yǔ)句可獲得的更廣泛的鎖定操作领追。此實(shí)現(xiàn)允許更靈活的結(jié)構(gòu),可以具有差別很大的屬性响逢,可以支持多個(gè)相關(guān)的 Condition 對(duì)象(Condition實(shí)現(xiàn)類ConditonObject來實(shí)現(xiàn)線程的通知/與喚醒機(jī)制绒窑,關(guān)于Condition傳送門
)。
2舔亭、 Lock的實(shí)現(xiàn)類ReentrantLock
ReentrantLock是根據(jù)AQS實(shí)現(xiàn)的獨(dú)占鎖(exclusive)些膨。
3、 AQS簡(jiǎn)介
AQS全稱AbstractQueuedSynchronizer,是java并發(fā)包中的一個(gè)類钦铺,該類更像是一個(gè)框架(模板方法模式)订雾,提供了一些模板方法供子類實(shí)現(xiàn),從而實(shí)現(xiàn)了不同的同步器矛洞,如下圖所示葬燎。ReentrantLock,ReentrantReadWriteLock缚甩,CountDownLatch、ThreadPoolExecutor等
這些常見類都使用了AQS窑邦。
4擅威、 ReentrantLock類體系
ReentrantLock類體系結(jié)構(gòu)
5、Lock使用
eg:加鎖/解鎖偽代碼
Lock lock = new xxxLock();
try{
// 加鎖
lock.lock();
balabala作相應(yīng)業(yè)務(wù)
} finally{
// 解鎖
lock.unlock();
}
6冈钦、AQS原理:
6.1郊丛、AQS內(nèi)存模型
AQS內(nèi)存模型
6.2、AQS類體系
AQS類體系結(jié)構(gòu)
6.3瞧筛、AQS模板方法
模板方法
抽象方法
6.4厉熟、Node節(jié)點(diǎn)
Node節(jié)點(diǎn)
6.5、CHL同步隊(duì)列
CHL同步隊(duì)列
6.6较幌、同步狀態(tài)獲茸嵘(acquire)與釋放(release)
獲取&釋放同步狀態(tài)
6.7、線程阻塞與喚醒
線程掛起&喚醒
7乍炉、AQS-產(chǎn)品之一ReentrantLock:
7.1绢片、圖解:獲取鎖滤馍、釋放鎖、入同步隊(duì)列
背景:Thread-A 底循、Thread-B巢株、Thread-C順序獲取鎖,模擬內(nèi)存中同步隊(duì)列變化熙涤。還要一種特殊情況:Thread-D獲取鎖失敗阁苞,同時(shí)入同步隊(duì)列失敗(最倒霉的線程D)祠挫。
Thread-A獲得重入鎖
Thread-B獲得鎖失敗那槽,入同步隊(duì)列
Thread-C入同步隊(duì)列
最倒霉的Thread-D加鎖失敗、入隊(duì)失敗g
如果node!=tail茸歧,不是尾節(jié)點(diǎn)倦炒,尾結(jié)點(diǎn)是Thread-X
走uparkSuccessor(node)
假設(shè)內(nèi)存中Thread-N中的 waitStatus=1
分析下第7-3步驟為何要倒序循環(huán)喚醒節(jié)點(diǎn)?
為何倒序喚醒節(jié)點(diǎn)软瞎?
7.2逢唤、公平鎖&非公平鎖
thread-6公平鎖入隊(duì)
thread-6非公平鎖入隊(duì)
8、面試常見問題:
- 1涤浇、公平鎖(FairSync)和非公平鎖(NonfairSync)的區(qū)別鳖藕?
鎖的公平性:獲取鎖順序而言的。
共同點(diǎn):都是繼承自ReentrantLock內(nèi)部類Sync只锭。
差異:- 公平鎖著恩,那么鎖的獲取順序就應(yīng)該符合請(qǐng)求的絕對(duì)時(shí)間順序,也就是 FIFO蜻展。
- 非公平鎖喉誊,在獲取鎖的時(shí)候,會(huì)先通過 CAS 進(jìn)行搶占纵顾。
另外公平鎖
判斷條件多了hasQueuedPredecessors()
方法伍茄,也就是加入了[同步隊(duì)列中當(dāng)前節(jié)點(diǎn)是否有前驅(qū)節(jié)點(diǎn)]的判斷,如果該方法返回 true施逾,則表示有線程比當(dāng)前線程更早地請(qǐng)求獲取鎖敷矫, 因此需要等待前驅(qū)線程獲取并釋放鎖之后才能繼續(xù)獲取鎖。
公平鎖加鎖方法:
// 公平鎖-獲取鎖的方法
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 同步隊(duì)列中當(dāng)前節(jié)點(diǎn)是否有前驅(qū)節(jié)點(diǎn)
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
非公平鎖加鎖方法:
final void lock() {
// 嘗試CAS加鎖
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 第一次嘗試失敗后汉额,走父類通用加鎖邏輯
acquire(1);
}
// 父類模板方法回調(diào)tryAcquire方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- 2曹仗、ReentrantLock如何處理線程中斷的?
阻塞隊(duì)列使用的LockSupport.park();
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
因?yàn)長(zhǎng)ockSupport.park(),無法響應(yīng)Thread.interrupt(); 所以當(dāng)unpark()后使用Thread.interrupted()來判斷線程是否有中斷過蠕搜。如果中斷過整個(gè)喚醒的線程在外層方法會(huì)繼續(xù)執(zhí)行一次中斷怎茫,詳情源碼如下:
image.png
image.png
static void selfInterrupt() {
Thread.currentThread().interrupt();
}