zoukankan      html  css  js  c++  java
  • 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实现自己的逻辑。

  • 相关阅读:
    poj 2485 Highways 最小生成树
    hdu 3415 Max Sum of MaxKsubsequence
    poj 3026 Borg Maze
    poj 2823 Sliding Window 单调队列
    poj 1258 AgriNet
    hdu 1045 Fire Net (二分图匹配)
    poj 1789 Truck History MST(最小生成树)
    fafu 1181 割点
    减肥瘦身健康秘方
    人生的问题
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14030995.html
Copyright © 2011-2022 走看看