總結(jié)一下ReetrantLock
ReetrantLock分為公平鎖兴猩,以及非公平鎖介陶,默認(rèn)情況下是非公平鎖嵌言,分別總結(jié)一下這兩種使用的異同點(diǎn)。
ReentrantLock 的成員變量有
private final Sync sync;
//這個(gè)就是AQS
abstract static class Sync extends AbstractQueuedSynchronizer
首先使用ReetrantLock的時(shí)候,會(huì)先new一個(gè)出來(lái)這時(shí)候,默認(rèn)的構(gòu)造函數(shù)是構(gòu)造一個(gè)非公平鎖
public ReentrantLock() {
sync = new NonfairSync();
}
然后嘗試調(diào)用加鎖的時(shí)候箭跳,其實(shí)調(diào)用的是sync的lock方法
public void lock() {
sync.lock();
}
然后就會(huì)調(diào)用非公平鎖的lock方法
final void lock() {
//首先進(jìn)行cas操作箕戳,把state的狀態(tài)從0變成1舀射,非公平鎖和公平鎖的區(qū)別就是,首先會(huì)進(jìn)行一次CAS操作,如果線程拿到了鎖氧猬,那就搶占了資源,這樣的話坏瘩,可能新的線程會(huì)優(yōu)先于已經(jīng)在隊(duì)列里的那些線程拿到鎖盅抚,這樣不是按順序的,就是非公平的了
if (compareAndSetState(0, 1))
//如果cas成功了倔矾,aqs的持有線程就是當(dāng)前的線程
setExclusiveOwnerThread(Thread.currentThread());
else
//沒(méi)有拿到鎖泉哈,那就調(diào)用的AQS中的acquire
acquire(1);
}
如果當(dāng)前線程沒(méi)有拿到鎖,那么就去執(zhí)行acquire(1)方法
/**
* 這里有幾個(gè)步驟
* 1.先嘗試獲取一下tryAcquire破讨,
* 2.如果獲取不到鎖丛晦,那就將當(dāng)前線程添加到節(jié)點(diǎn)中addWaiter(Node.EXCLUSIVE) 添加到了CLH中
* 3.acquireQueued通過(guò)自旋的方式不斷的獲取鎖
* 4.最終拿到了之后會(huì)中斷自己
* @param arg
*/
public final void acquire(int arg) {
//如果沒(méi)有獲取成功,那么就要添加到隊(duì)列中了
//再嘗試獲取一下提陶,如果獲取不到烫沙,就先加入
if (!tryAcquire(arg) &&
//獨(dú)占模式,添加了一個(gè)隙笆,然后返回當(dāng)前節(jié)點(diǎn)
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
//當(dāng)前線程自我中斷
selfInterrupt();
}
}
tryAcquire方法最后會(huì)調(diào)用ReetrantLock的Sync的nonfairTryAcquire方法
final boolean nonfairTryAcquire(int acquires) {
//獲取當(dāng)前線程
final Thread current = Thread.currentThread();
//拿到當(dāng)前鎖的state
int c = getState();
//如果是0的話锌蓄,就把a(bǔ)qs的state設(shè)置為acquires,當(dāng)前就可以拿到鎖了
if (c == 0) {
//嘗試一下cas撑柔,如果成功就可以拿到鎖了
if (compareAndSetState(0, acquires)) {
//設(shè)置當(dāng)前線程為當(dāng)前l(fā)ock所擁有的鎖
setExclusiveOwnerThread(current);
return true;
}
}
//如果當(dāng)前的鎖就是被這個(gè)線程拿到
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//那么就是設(shè)置可重入狀態(tài)了瘸爽,這個(gè)要加
setState(nextc);
return true;
}
//否則當(dāng)前線程無(wú)法獲取
return false;
}
其中addWaiter方法
/**
* Creates and enqueues node for current thread and given mode.
* 就是當(dāng)前線程沒(méi)有拿到鎖的時(shí)候
* 1.如果尾部節(jié)點(diǎn)有值,那么加到最后一個(gè)返回
* 2.如果尾部節(jié)點(diǎn)沒(méi)有值铅忿,添加一個(gè)節(jié)點(diǎn)剪决,然后返回
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/
private Node addWaiter(Node mode) {
/**
* 當(dāng)前線程構(gòu)建一個(gè)node,是獨(dú)占模式的
* new 出來(lái)的這個(gè)節(jié)點(diǎn)的結(jié)構(gòu)是
* node(當(dāng)前線程檀训,nextWaiter是個(gè)mode)
*/
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
//如果尾節(jié)點(diǎn)不為空
if (pred != null) {
//將當(dāng)前節(jié)點(diǎn)的前驅(qū)指向尾部節(jié)點(diǎn)
node.prev = pred;
//將當(dāng)前節(jié)點(diǎn)設(shè)置為尾部節(jié)點(diǎn)柑潦,使用cas設(shè)置一下
if (compareAndSetTail(pred, node)) {
//現(xiàn)在的尾部借點(diǎn)就是 node了,然后再將pred的next指向尾部峻凫,然后返回
pred.next = node;
return node;
}
}
//如果尾部節(jié)點(diǎn)是空的渗鬼,就建立一節(jié)點(diǎn),頭和尾都指向這個(gè)節(jié)點(diǎn)荧琼,而且自己指向自己[自己的pre指向自己譬胎,自己的next指向自己]
enq(node);
return node;
}
private Node enq(final Node node) {
//自旋操作
for (;;) {
//線程A:第一次的時(shí)候 tail是null,需要初始化
//線程A:第二次進(jìn)來(lái)的時(shí)候命锄,由于是自旋 此時(shí)t=head=tail
Node t = tail;
if (t == null) { // Must initialize 必須進(jìn)行初始化
//尾巴節(jié)點(diǎn)是空的堰乔,先初始化一下head節(jié)點(diǎn),再將head節(jié)點(diǎn)給tail節(jié)點(diǎn)
if (compareAndSetHead(new Node()))
tail = head;
} else {
//線程A:第二次進(jìn)來(lái)的時(shí)候累舷,由于是自旋浩考,
//當(dāng)前節(jié)點(diǎn)的前驅(qū)是t,有可能自己指向了自己
node.prev = t;
//這一步相當(dāng)于把tail的引用指向了新增的node
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
執(zhí)行如圖
最后重點(diǎn)的自旋獲取鎖的方法acquireQueued