1.简单的使用
// CountDownLatch 需要注意的地方有三个地方,如代码中标注
// 当前代码执行时会阻塞的 因为在 ② 中设置的值为 4 ,但只有3个线程过来,所以一直在阻塞
// 就像打麻将一样,还差一个人
public class CountdownLatchTest implements Runnable{
CountDownLatch countDownLatch;
public CountdownLatchTest(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("CountDownLatch peform ..."+Thread.currentThread().getName());
countDownLatch.countDown(); // 注意 ①
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(4); // 注意 ②
for(int i = 0; i < 3; i++){ // 注意 ③
Thread thread = new Thread(new CountdownLatchTest(countDownLatch));
thread.start();
Thread.currentThread().sleep(500);
}
System.out.println("等待线程完成...");
countDownLatch.await(); // 注意 ④
System.out.println("countDownLatch 执行完成");
}
}
2.看看源码吧
/**
* 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;
}
}
}
CountDownLatch 里面定义了一个类 Sync,这个类 Sync 继承了 AbstractQueuedSynchronizer,它的初始化调用的时 setState 方法,getCount调用的是getState方法。
当每执行一次 countDown 方法时,它都会释放一份资源,调用方法过程为:
外部调用 countDown 方法 --> 内部调用父类 releaseShared 方法,并传入参数1(表示释放一份锁资源)—>调用 tryReleaseShared 方法,并传来参数 1,tryReleaseShared 方法由子类实现 —> 真正实现在子类中,代码如下: 死循环获取当前锁资源数量
protected boolean tryReleaseShared(int releases) { // 传入需要释放的资源数量,这里是 1
// 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; // 这里判断是否锁资源释放完了,这里决定了是否还会继续阻塞下去,如下代码
}
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { // 更具返回值,决定死否释放资源
doReleaseShared(); // 释放资源,线程继续,如果不能理解的话,建议去看看AQS源码,会比较难,但看完 AQS 后看这个会感觉好简单
return true;
}
return false;
}