概述
允许一个或多个线程等待其他线程完成操作。
定义一个初始值,当初始值经过调用每次递减,最后递减到0的时候,线程才从指定点开始继续向下执行,否则在调用wait方法的地方一直阻塞(也可以等待一定时间后不再阻塞),在调用countDown方法的地方不阻塞。
在调用await()方法处阻塞,每次递减调用countDown()方法。
使用方法
package countlatch;
import java.util.concurrent.CountDownLatch;
/**
* CountDownLatch允许一个或多个线程等待其他线程完成操作
* 原理是不停的检查join的线程是否存活,活着就让当前线程永远等待下去(wait(0))
* join的线程终止后,线程的this.notifyAll()方法会被调用(由JVM实现)
* 可以在一个线程的N个点调用countDown方法,也可以在多个线程中调用
* 只需将这个CountDownLatch的引用传递到线程里面
*
* @author bamboo
*
*/
public class TestCountdownLatch {
static CountDownLatch count = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
ThreadA a = new ThreadA(count);
ThreadA b = new ThreadA(count);
new Thread(a).start();
new Thread(b).start();
count.await();
System.out.println("test CountDownLatch success");
}
}
package countlatch;
import java.util.concurrent.CountDownLatch;
public class ThreadA implements Runnable{
CountDownLatch countdownLatch;
@Override
public void run() {
synchronized(ThreadA.class) {
try {
for(int i = 0;i < 5;i++) {
Thread.sleep(1000);
System.out.println("i = " + i);
}
System.out.println(Thread.currentThread().getName() + " is running over");
countdownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadA(CountDownLatch countdownLatch){
this.countdownLatch = countdownLatch;
}
}
结果:
i = 0
i = 1
i = 2
i = 3
i = 4
Thread-0 is running over
i = 0
i = 1
i = 2
i = 3
i = 4
Thread-1 is running over
test CountDownLatch success
从以上输出可以看出,线程会一直阻塞在wait()方法之前,当计数归0继续向下执行。
源码
自JDK1.5引入,跟它一起引入的还有CyclicBarrier、Semaphore
CountDownLatch是同步控制的,并且使用队列同步器来计数。
* @since 1.5
* @author Doug Lea
*/
public class CountDownLatch {
这是CountDownLatch的初始化方法,传入一个计数开始。Sync是一个静态内部类,继承自AQS
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync类源码如下:
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
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))
return nextc == 0;
}
}
}
AQS使用的模板方法,tryReleaseShared和tryAcquireShared是共享式释放和获取锁的方法。compareAndSetState使用CAS设置当前状态,参数分别是期望值和新值,该方法可以保证状态设置的原子性。
wait() 方法的源码
直接调用wait()方法,线程在计数未归0之前一直阻塞,直到归0继续执行。也可以设置等待时间,当达到这一定的时间还未归0仍然会停止阻塞,让线程继续执行。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}