一、CountDownLatch
CountDownLatch的主要应该场景是,可以用来等待其他线程处理完某个任务后再执行主流程,比如,现在我们有一个运算结果依赖于其它几个线程的运行结果,类似这样的场景就可以考虑用CountDownLatch来实现,CountDownLatch是基于AQS实现的,使用了AQS提供的共享模式。
二、先看一个使用的简单例子
启动2个子线程,当2个子线程运行结束后,main线程来开始处理。
public class CountDownLatchExample {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(2);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("第一个子线程运行开始:" + System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一个子线程运行结束:" + System.currentTimeMillis());
latch.countDown();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("第二个子线程运行开始:" + System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二个子线程运行结束:" + System.currentTimeMillis());
latch.countDown();
}
}).start();
try {
latch.await();
System.out.println("子线程全部运行结束" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可能的运行效果
第一个子线程运行开始:1506062565771
第二个子线程运行开始:1506062565779
第一个子线程运行结束:1506062566772
第二个子线程运行结束:1506062566779
子线程全部运行结束1506062566780
可以看到,当2个子线程跑完后,主线程才开始执行。
三、源码分析
CountDownLatch使用了AQS里面的原子int域 state来记录Count的数量,采用的是AQS提供的共享模式。
在CountDownLatch里面,定义了一个Sync内部类
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
//AQS里面的state用来表示count
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
//await的时候, 如果当前count为0,那么方法返回1,
//按照之前对AQS的分析,请求成功,并唤醒同步队列里下一个共享模式的线程(这里都是共享模式的)。
//如果当前count不为0,那么方法返回-1,请求失败,当前线程最终会被阻塞(之前会不止一次调用tryAcquireShared)。
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
//释放锁
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
//获取当前内部的int域的值
int c = getState();
//如果已经为0,说明已经不用释放了
if (c == 0)
return false;
//count值-1
int nextc = c-1;
//CAS设置最新的值
if (compareAndSetState(c, nextc))
//最后如果count=0了,那么就唤醒所有等待的线程,类比于上面的主线程
return nextc == 0;
}
}
}
CountDownLatch持有Sync的引用
//持有静态内部类Sync的引用
private final Sync sync;
初始化countDownLatch,可以看到传入的count,最后实际上是对state进行了赋值
/**
* 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);
}
当调用await的时候,表示阻塞主当前线程
/**
* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
*
* <p>If the current count is zero then this method returns immediately.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of two things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
* </ul>
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* @throws InterruptedException if the current thread is interrupted
* while waiting
*/
public void await() throws InterruptedException {
//实际会调用AQS里面的方法
sync.acquireSharedInterruptibly(1);
}
/**
* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted},
* or the specified waiting time elapses.
*
* <p>If the current count is zero then this method returns immediately
* with the value {@code true}.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of three things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread; or
* <li>The specified waiting time elapses.
* </ul>
*
* <p>If the count reaches zero then the method returns with the
* value {@code true}.
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* <p>If the specified waiting time elapses then the value {@code false}
* is returned. If the time is less than or equal to zero, the method
* will not wait at all.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the {@code timeout} argument
* @return {@code true} if the count reached zero and {@code false}
* if the waiting time elapsed before the count reached zero
* @throws InterruptedException if the current thread is interrupted
* while waiting
*/
//如果Count=0,那么返回true,如果不为0,会阻塞,直到count=0或者超时或者线程被中断
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
//支持超时
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
当调用countDown方法时,表示对同步计数器-1
/**
* Decrements the count of the latch, releasing all waiting threads if
* the count reaches zero.
*
* <p>If the current count is greater than zero then it is decremented.
* If the new count is zero then all waiting threads are re-enabled for
* thread scheduling purposes.
*
* <p>If the current count equals zero then nothing happens.
*/
//每次调用counDown的时候,同步计数器-1,最后当count=0时,唤醒所有等待线程,如果Count本身就是0了,那么什么都不做
public void countDown() {
sync.releaseShared(1);
}
最后,看一下CountDownLatch提供了其它方法,
/**
* Returns the current count.
*
* <p>This method is typically used for debugging and testing purposes.
*
* @return the current count
*/
public long getCount() {
//获取此时同步计数器的个数
return sync.getCount();
}
/**
* Returns a string identifying this latch, as well as its state.
* The state, in brackets, includes the String {@code "Count ="}
* followed by the current count.
*
* @return a string identifying this latch, as well as its state
*/
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
}
至此,CountDownLatch分析完毕。