zoukankan      html  css  js  c++  java
  • CountDownLatch 源码分析

    CountDownLatch 源码分析:

    1:CountDownLatch数据结构

    成员变量 Sync类型对象

    private final Sync sync; Sync是继承AQS的一个类,CountDownLatch是通过AQS和CAS来实现它的锁的功能的;

    2构造方法:

    public CountDownLatch(int count) {  //需要等待调用countDown() 的次数 这个例子中count=5 来举例说明

            if (count < 0) throw new IllegalArgumentException("count < 0");

            this.sync = new Sync(count);  //创建Sync对象,AQS的子类

    }

    Sync(int count) {

                setState(count);   //设置AQS类中state=count=5 state 是volitle修饰的

            }

    3:await 方法分析:

    public void await() throws InterruptedException { 

            sync.acquireSharedInterruptibly(1);  //调用AQS中的acquireSharedInterruptibly方法

    }

    AQS. acquireSharedInterruptibly()  源码如下:

    public final void acquireSharedInterruptibly(int arg)   // arg=1

                throws InterruptedException {

            if (Thread.interrupted())   // 当前线程是否中断状态 如果中断则抛出异常

                throw new InterruptedException();

            if (tryAcquireShared(arg) < 0)  //尝试获取共享锁

                doAcquireSharedInterruptibly(arg);

    }

    tryAcquireShared方法如下:

    protected int tryAcquireShared(int acquires) {  // acquires=1

                return (getState() == 0) ? 1 : -1;  //state=5 表明未获取到锁,则返回 -1

            }

    返回-1后满足tryAcquireShared(arg) < 0这个条件,则进入doAcquireSharedInterruptibly(arg);

    这个方法:下面对这个方法分析:

    在分析这个源码之前,说明下 for(;;) 的作用:不断的轮询,相当于while(true)

    private void doAcquireSharedInterruptibly(int arg)    // arg=1

            throws InterruptedException {

    创建当前线程的节点,并且锁的模型是 共享锁 将其添加到AQS CLH队列的末尾

            final Node node = addWaiter(Node.SHARED);

            boolean failed = true;

            try {

                for (;;) {   //轮询以下代码的逻辑

                    final Node p = node.predecessor(); //获取前继节点

                    if (p == head) {  //前继节点是表头则进入以下逻辑

                        int r = tryAcquireShared(arg); //尝试获取锁 这里state=5 获取锁失败

                        if (r >= 0) {

                            setHeadAndPropagate(node, r);

                            p.next = null; // help GC

                            failed = false;

                            return;

                        }

                    }

    //前继节点不是表头或者获取共享锁失败则进入以下逻辑,当前挂起,一直到获取到共享锁

                    if (shouldParkAfterFailedAcquire(p, node) && 

                        parkAndCheckInterrupt())  //当前线程挂起,一直等待

                        throw new InterruptedException();

                }

            } finally {

                if (failed)

                    cancelAcquire(node);

            }

    }

    下面对shouldParkAfterFailedAcquire 这个方法进行分析,这个之前在公平锁中有过分析

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {

            int ws = pred.waitStatus;  //for(;;)第一次进入是waitStatus=0

            if (ws == Node.SIGNAL)

               return true;    //第二次进入的时候返回 true

            if (ws > 0) {

               

    do {

                    node.prev = pred = pred.prev;

                } while (pred.waitStatus > 0);

                pred.next = node;

            } else {

              

    compareAndSetWaitStatus(pred, ws, Node.SIGNAL); //设置waitStatus=-1

            }

            return false;

        }

    接下来分析下 countDown方法:

    public void countDown() {

            sync.releaseShared(1);

        }

    releaseShared的方法如下:  目的  将AQS中的state -1,当state减到0的时候返回true

    public final boolean releaseShared(int arg) {  // arg=1

            if (tryReleaseShared(arg)) {

                doReleaseShared();   //这段代码的作用是unpark 被await 的线程;

    具体的实现是:调用后继节点的LockSupport.unpark(s.thread); 这里的s节点就是head节点的后继节点;也就是前面调用await被挂起的线程节点

                return true;

            }

            return false;

        }

    通过这里的countDown方法,就和之前的await()方法呼应起来了。实现了,某一个线程等待其他线程执行结束后再执行这个线程

  • 相关阅读:
    20160421
    20160420笔记
    第一个随笔
    搬家
    OO第十五次作业
    OO第三次博客作业
    OO5-7次作业总结
    从入门到不放弃——OO第一次作业总结
    第八次团队作业——系统设计和任务分配
    第七次作业-团队选题报告和需求规格说明书
  • 原文地址:https://www.cnblogs.com/beppezhang/p/11214540.html
Copyright © 2011-2022 走看看