CountDownLatch底层原理和Semaphore差不多,就简单记录下吧!
可以查看我的上一篇文章比较详细—> Semaphore底层原理
一、CountDownLatchDemo
1)设置了资源数量为2;
2)资源数量还没减到0,countDownLatch.await()一直将线程阻塞;
3)当资源数量减到0的时候,countDownLatch.countDown(),开始解锁。
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(2);
for (int i = 0; i < 3; i++) {
//提醒有新的用户接单了:甲买两杯奶茶,乙买一杯奶茶
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "做奶茶");
try {
Thread.sleep(new Random().nextInt(5000));
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
System.out.println(Thread.currentThread().getName() + "做好了");
try {
countDownLatch.await();
System.out.println("甲的订单好了,等待外卖小哥");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, i + "号员工").start();
}
}
}
运行结果
二、加锁阶段
在new CountDownLatch(3)的时候设置了state=3
;
protected final void setState(int newState) {
state = newState;
}
点击await()进入acquireSharedInterruptibly()
tryAcquireShared()对state进行减一操作
,为0后再减一
,则if语句为true进入doAcquireSharedInterruptibly()
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
doAcquireSharedInterruptibly()
addWaiter(Node.SHARED)进入等待队列
,设置prev的waitStatus为-1;
如果CAS成功修改state
则等待队列的head出队,如果next为空,则直接唤醒
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED); // 进入等待队列
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) && // 设置prev的waitStatus为-1
parkAndCheckInterrupt()) // 阻塞线程
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
三、解锁阶段
countDownLatch.countDown()方法进行解锁
进入releaseShared(),点进tryReleaseShared()
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
tryReleaseShared()
对state进行CAS修改减一操作
,如果state为0
后返回true,进入doReleaseShared()
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1; // 减一
if (compareAndSetState(c, nextc)) //CAS修改
return nextc == 0;
}
}
doReleaseShared()进行唤醒下一个线程
,在unparkSuccessor中将waitStatus设置为0
后,LockSupport.unpark下一个线程
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h); // 唤醒下一个线程
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}