zoukankan      html  css  js  c++  java
  • JUC锁框架源码阅读-CountDownLatch

    说明

    使用方式参考:https://www.cnblogs.com/LQBlog/p/8983019.html

    初始化

    main 

       public static void main(String[] args) throws InterruptedException {
            //<1>初始化
            CountDownLatch countDownLatch=new CountDownLatch(3);
        }

    <1>初始化

      public CountDownLatch(int count) {
            if (count < 0) throw new IllegalArgumentException("count < 0");
            //初始化内部类的对象 Sync 改类继承AQS
            this.sync = new CountDownLatch.Sync(count);
        }
    
        private static final class Sync extends AbstractQueuedSynchronizer {
            private static final long serialVersionUID = 4982264981922014374L;
    
            Sync(int count) {
                //调用父类的设置所属状态 这里就表名锁以及被持有量额
                setState(count);
            }
    
        }

    await等待

    main

     public static void main(String[] args) throws InterruptedException {
            //初始化 默认设置AQS state为3 表示锁已经被持有
            CountDownLatch countDownLatch=new CountDownLatch(3);
            //<1>本质是加锁
            countDownLatch.await();
        }

    1.因为初始化设置了栅栏数量 AQS state

    2.实现获取共享锁的是判断 state是否>0 大于0则获取失败 交给AQS 放入CLH队列等待

    <1>await

     public void await() throws InterruptedException {
            //<2>调用父类获取AQS方法
            sync.acquireSharedInterruptibly(1);
        }

    <2>doAcquireSharedInterruptibly

    详情可以参考《AQS源码阅读》

     /**
         * Acquires in shared interruptible mode.
         * @param arg the acquire argument
         */
        private void doAcquireSharedInterruptibly(int arg)
                throws InterruptedException {
            //创建共享节点 并插入队列
            final AbstractQueuedSynchronizer.Node node = addWaiter(AbstractQueuedSynchronizer.Node.SHARED);
            boolean failed = true;
            try {
                //自旋
                for (;;) {
                    //获得节点的上一个节点
                    final AbstractQueuedSynchronizer.Node p = node.predecessor();
                    //如果他的节点就是节点头 尝试获取锁 因为并发情况节点头可能释放了
                    if (p == head) {
                        //<3>子类实现获取共享锁方法模板模式
                        int r = tryAcquireShared(arg);
                        if (r >= 0) {
                            //重新设节点头 并尝试唤醒其他等待节点
                            setHeadAndPropagate(node, r);
                            p.next = null; // help GC
                            failed = false;
                            return;
                        }
                    }
                    //如果前一个节点p的状态是Node.SIGNAL,就是调用<6>parkAndCheckInterrupt方法阻塞当前线程
                    if (shouldParkAfterFailedAcquire(p, node) &&
                            parkAndCheckInterrupt())
    
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    //<此时前一个节点pred的状态只能是0或者PROPAGATE,不可能是CONDITION状态
                    // CONDITION(这个是特殊状态,只在condition列表中节点中存在,CLH队列中不存在这个状态的节点)
                    // 将前一个节点pred的状态设置成Node.SIGNAL,这样在下一次循环时,就是直接阻塞当前线程
                    cancelAcquire(node);
            }
        }

    <3>tryAcquireShared

    java.util.concurrent.CountDownLatch.Sync#tryAcquireShared

       protected int tryAcquireShared(int acquires) {
            //获取state 前面我们默认值设置的3 所以await是获取不到的 所以加入AQS队列
            return (getState() == 0) ? 1 : -1;
        }

    countDown释放

    main

      public static void main(String[] args) throws InterruptedException {
            //初始化 默认设置AQS state为3 表示锁已经被持有
            CountDownLatch countDownLatch=new CountDownLatch(3);
            //<1>本质是释放锁
            countDownLatch.countDown();
        }

    1.每次释放 栅栏数量-1(AQS sate) 如果state

    2.当state数量大于==0 则返回释放成功 交给AQS 唤醒AQS阻塞队列 这个时候因为state等于0 所以都获取成功锁

    <1>countDown

     public void countDown() {
            //<2>调用内部内对象释放共享锁的方法 继承自AQS
            sync.releaseShared(1);
        }

    <2>releaseShared

    可以参考《AQS源码阅读》

     // 释放共享锁
        public final boolean releaseShared(int arg) {
            // <3>模板模式 抽象方法尝试释放共享锁
            if (tryReleaseShared(arg)) {
                //唤醒等待共享锁的线程
                doReleaseShared();
                return true;
            }
            return false;
        }

    <3>tryReleaseShared

    java.util.concurrent.CountDownLatch.Sync#tryReleaseShared

       protected boolean tryReleaseShared(int releases) {
            //自旋
            for (;;) {
                //获得状态
                int c = getState();
                //如果已经等于0 返回false
                if (c == 0)
                    return false;
                int nextc = c-1;
                //cas设置状态-1 当成功并且等于0 表示释放成功 会唤醒阻塞线程
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
  • 相关阅读:
    ASP.Net Cms
    GetHashCode函数所存在的陷阱
    NH的系统架构
    Icomparable<T> 和 Icomparaer<T> 实现顺序关系
    《创业法典》:用流程图告诉你如何创业
    创业之前,网站先行
    杨卫华:新浪微博的架构发展历程
    技术开发人员为什么会无奈苦逼?
    使用面向对象的、完整的单点登录功能
    SilverLight之我见
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15224217.html
Copyright © 2011-2022 走看看