CountDownLatch简单分析

6月 17th, 2016 1,658 留下评论 阅读评论

也是利用AQS实现的一个变种,用来预先设置一个阈值(任务数)后主线程调用await()持续阻塞,然后由其他线程执行任务,执行完后调用countDown()将阈值减1,当所有任务执行完毕,阈值减为0,主线程await()被唤醒跳出阻塞,继续执行。

使用例子

public class CountDownLatchDemo {
 
    public static void main(String[] args) throws InterruptedException {
    	CountDownLatch latch = new CountDownLatch(2); // 两个任务线程
    	Worker worker1 = new Worker("A", latch);
    	Worker worker2 = new Worker("B", latch);
    	worker1.start();//
    	worker2.start();//
 
    	latch.await(); // 阻塞等待所有Worker线程结束
        System.out.println("all work done");
    }
 
    static class Worker extends Thread {
    	private CountDownLatch latch;
    	public Worker(String workerName, CountDownLatch latch){
    	    this.latch = latch;
    	}
    	public void run(){
	    try{
	        doWork();
	    }
            // 必须放在finally中保证能够释放(不然出异常主线程无法恢复)
	    finally{
	        latch.countDown(); //线程执行结束, 计数器减1
	    }
    	}
    } 
}

源码分析

针对AQS的分析见:可重入锁、ReentrantLock、AQS、Condition 和 ReentrantReadWriteLock简单分析

CountDownLatch的内置Sync类相当简单

  • 构造函数,初始化count值,写入AQS的state(相当于已经有count的对象持有锁)
  • 主线程调用await()方法,就是执行AQS.acquireSharedInterruptibly,而Sync.tryAcquireShared,只有当state == 0才能够acquire成功(即只有当count减为0,await才会跳出阻塞)
  • 其他线程调用countDown()方法,就是执行AQS.releaseShared(1),而Sync.tryReleaseShared,最简单的无限循环阻塞保证release成功
  • 多于count数量的执行countDown()方法,不会再更新state值,state减为0就不变了
  • 多次await也没有意义,在state==0后,await操作就是共享加锁,都可以瞬间成功
Categories: Java 标签:,
  1. 还没有评论呢。