使用实例
class CountDownLatchThread extends Thread {
private CountDownLatch countDownLatch;
public CountDownLatchThread(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(10*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
}
}
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(2);
CountDownLatchThread thread1 = new CountDownLatchThread(countDownLatch);
thread1.start();
CountDownLatchThread thread2 = new CountDownLatchThread(countDownLatch);
thread2.start();
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end");
}
}
实例化
CountDownLatch(int count)构造函数里实例化了一个属性的值sync。Sync是CounDownLatch私有的不可变的静态内部类
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync继承了队列同步器AbstractQueuedSynchronizer(简称AQS),提供了一个修改AQS的state变量的构造函数。重写了AQS的tryAcquireShared和tryReleaseShared方法。
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
//修改AQS state变量的值
Sync(int count) {
setState(count);
}
//获取state变量的值
int getCount() {
return getState();
}
//判断state变量的值是否等于0,如果等于0,返回1;如果不等于0,返回-1。
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
//无限循环直到state的值为0或者cas修改state的值成功。
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
//获取state的值
int c = getState();
//如果state的值为0,直接返回false。
if (c == 0)
return false;
//state值减去1
int nextc = c - 1;
//cas修改state的值
if (compareAndSetState(c, nextc))
//判断state的值是否等于0,如果等于0,返回true,如果不等于0,返回false。
return nextc == 0;
}
}
}
await()方法
CountDownLatch的await方法调用了AQS的acquireSharedInterruptibly方法,入参是1。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
Thread.interrupted()判断线程是否是中断状态,如果是,返回true。
tryAcquireShared(arg)判断state值是否等于0。等于0,返回1;不等于0,返回-1。
如果线程不是中断的,并且state的值不等于0,就会调用AQS的acquire方法。
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted() ||
(tryAcquireShared(arg) < 0 &&
acquire(null, arg, true, true, false, 0L) < 0))
throw new InterruptedException();
}
AQS#acquire方法将当前线程加入到队列中。
(1)第一次循环:first=false,node=null,pred=null,当first为true或者pred为null会去尝试获取锁,如果tryAcquireShared方法返回1,表示锁没有被占用。acquire方法直接返回1。如果tryAcquireShared方法返回-1,表示还有线程没有释放锁(也就是没有countDown),实例化node节点。
(2)第二次循环:first=false,node!=null,pred=node.prev=null,调用tryAcquireShared方法,如果state值不是0,初始化头结点,头尾结点指向相同结点。
(3)第三次循环:first=false,node!=null,pred=node.prev=null,如果调用tryAcquireShared方法返回不是1,cas将尾结点设置为node结点。如果设置成功,将前尾结点的next结点设置为node结点。node结点的prev结点设置为前尾结点。
(4)第四次循环:first=false,pred != null,head=pred ⇒ first=true,如果调用tryAcquireShared方法返回不是1,node结点的state属性初始值是0,修改为等待状态。
(5)第五次循环:first=true,如果调用tryAcquireShared方法返回不是1,调用LockSupport.park方法阻塞当前线程。
first=true表示是第一个排队的结点,如果调用tryAcquireShared方法返回是1,且是第一个排队的结点,将当前结点作为头结点,并唤醒下一个结点。
final int acquire(Node node, int arg, boolean shared,
boolean interruptible, boolean timed, long time) {
Thread current = Thread.currentThread();
byte spins = 0, postSpins = 0; // retries upon unpark of first thread
boolean interrupted = false, first = false;
Node pred = null; // predecessor of node when enqueued
for (;;) {
if (!first && (pred = (node == null) ? null : node.prev) != null &&
!(first = (head == pred))) {
if (pred.status < 0) {
cleanQueue(); // predecessor cancelled
continue;
} else if (pred.prev == null) {
Thread.onSpinWait(); // ensure serialization
continue;
}
}
if (first || pred == null) {
boolean acquired;
try {
if (shared)
acquired = (tryAcquireShared(arg) >= 0);
else
acquired = tryAcquire(arg);
} catch (Throwable ex) {
cancelAcquire(node, interrupted, false);
throw ex;
}
if (acquired) {
if (first) {
node.prev = null;
head = node;
pred.next = null;
node.waiter = null;
if (shared)
signalNextIfShared(node);
if (interrupted)
current.interrupt();
}
return 1;
}
}
if (node == null) { // allocate; retry before enqueue
if (shared)
node = new SharedNode();
else
node = new ExclusiveNode();
} else if (pred == null) { // try to enqueue
node.waiter = current;
Node t = tail;
node.setPrevRelaxed(t); // avoid unnecessary fence
if (t == null)
tryInitializeHead();
else if (!casTail(t, node))
node.setPrevRelaxed(null); // back out
else
t.next = node;
} else if (first && spins != 0) {
--spins; // reduce unfairness on rewaits
Thread.onSpinWait();
} else if (node.status == 0) {
node.status = WAITING; // enable signal and recheck
} else {
long nanos;
spins = postSpins = (byte)((postSpins << 1) | 1);
if (!timed)
LockSupport.park(this);
else if ((nanos = time - System.nanoTime()) > 0L)
LockSupport.parkNanos(this, nanos);
else
break;
node.clearStatus();
if ((interrupted |= Thread.interrupted()) && interruptible)
break;
}
}
return cancelAcquire(node, interrupted, interruptible);
}
countDown方法
countDown方法是用于减少锁存器的计数,如果计数达到零,则释放等待线程。
public void countDown() {
sync.releaseShared(1);
}
如果state=0,就会唤醒等待队列的第一个等待线程。tryReleaseShared方法会CAS修改state的值直到成功。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
signalNext(head);
return true;
}
return false;
}
如果传入的结点不为空,且next结点不为空,status状态不是0,修改next结点的状态,然后调用LockSupport.unpark解除线程的阻塞状态。
private static void signalNext(Node h) {
Node s;
if (h != null && (s = h.next) != null && s.status != 0) {
s.getAndUnsetStatus(WAITING);
LockSupport.unpark(s.waiter);
}
}