Java CountDownLatch

1、CountDownLatch能干什么


可以理解为一个计数器。某个线程需要等待这个计数器减到0时,才会继续向下执行。而这个计数器可以在其他线程中递减。这就形成了这种情况,一个线程等待N个线程结束。
例子
import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {
	public static void main(String[] args) {
		final CountDownLatch cdl = new CountDownLatch(10);
		for (int i = 0; i < 10; i++){
			final int j = i;
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					int i = 0;
					while(i < Integer.MAX_VALUE){
						++i;
					}
					System.out.println(j);
					cdl.countDown();
				}
			}).start();
		}
		
		try {
			cdl.await();
			System.out.println("here");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

可以看到打印出的结果是,

5
0
2
4
6
8
3
7
1
9
here

在打印出了0-9后,才打印出here,主线程等待了10个子线程结束后才继续向下执行。

2、CountDownLatch分析


和FutureTask的实现相类似,其主要的工作都是在sync中实现,而sync就是AbstractQueuedSynchronizer的实例。
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

    private static final class Sync extends AbstractQueuedSynchronizer {

来看看await函数,
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
主要工作都是在sync中实现,来看看acquireSharedInterruptibly是如何实现的,
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

先通过tryAcquireShared来判断是否可以获得锁,如果可以则调用doAcquireSharedInterruptibly进行锁定。此时调用wait函数的线程被挂起,等待countDown唤醒。
		protected int tryAcquireShared(int acquires) {
			// 这里的state就是传入的参数count,当count捡到0的时候表示不可获得锁。否则可以获得锁
            return (getState() == 0) ? 1 : -1;
        }

那么来看看计数器是如何递减的。
    public void countDown() {
        sync.releaseShared(1);
    }

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

首先通过tryReleaseShared来判断是否可以释放锁,如果可以则调用doReleaseShared来释放锁定。
		protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
				// 获取当前计数
                int c = getState();
				// 如果c=0,则表示不可释放锁定
                if (c == 0)
                    return false;
				// 当前计数递减1
                int nextc = c-1;
				// 利用原子操作CAS,设置计数为nextc
                if (compareAndSetState(c, nextc))
					// 当nextc=0时,才表示可以释放锁定
                    return nextc == 0;
            }
        }

当反复调用countDown的时候,会不断进入tryReleaseShared函数,计数会从初始的count逐渐降低到0。这个时候就可以释放锁定了,也就是被阻塞的线程会被唤醒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值