CountDownLatch源码分析

一 使用场景

  在网上找了个例子,这个例子很好地说明了 CountDownLatch 的用法,概括地说就是主线程等待子线程执行完了,主线程接着执行

public class CountDownLatchTest {

    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(2);
        System.out.println("主线程开始执行…… ……");
        //第一个子线程执行
        ExecutorService es1 = Executors.newSingleThreadExecutor();
        es1.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println("子线程:"+Thread.currentThread().getName()+"执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                latch.countDown();
            }
        });
        es1.shutdown();

        //第二个子线程执行
        ExecutorService es2 = Executors.newSingleThreadExecutor();
        es2.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("子线程:"+Thread.currentThread().getName()+"执行");
                latch.countDown();
            }
        });
        es2.shutdown();
        System.out.println("等待两个线程执行完毕…… ……");
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("两个子线程都执行完毕,继续执行主线程");
    }
}

二 代码概况

  CountDownLatch的功能都是通过内部实现AQS来实现的

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;
            }
        }
    }

    private final Sync sync;

CountDownLatch的构造方法如下

public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

用户传进去的count就赋值给AQS的state

三  await源码分析

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

  之前分析过共享锁的代码,共享锁的主要逻辑还是要看用户实现的  tryAcquireShared 

protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

如果state不是0的话,返回-1,这样主线程就会进到队列中排队,并把自己阻塞起来,只能等待其他线程的唤醒

四 CountDown源码分析

每次调用 countDown() 固定是释放一个共享资源

 public void countDown() {
        sync.releaseShared(1);
    }
protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)//如果已经是0,那就没法释放了,返回false,这样就不会执行unpark方法
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))//减一成功后比较state是不是0,如果返回true
                    return nextc == 0;
            }
        }

如果state == 0,那么  tryReleaseShared 返回true,这样就会执行unpark的逻辑,这样主线程被唤醒,代码就可以继续执行了

五 总结

  CountDownLatch的源码不多,逻辑也不复杂,但是可以很好的看看如果通过继承AQS实现自己的逻辑。

posted on 2020-11-24 16:30  MaXianZhe  阅读(118)  评论(0编辑  收藏  举报

导航