当前位置: 首页 > news >正文

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()方法呼应起来了。实现了,某一个线程等待其他线程执行结束后再执行这个线程

转载于:https://www.cnblogs.com/beppezhang/p/11214540.html

相关文章:

  • HashMap 源码分析 基于jdk1.8分析
  • ReentrantLock 锁释放源码分析
  • ReentrantReadWriteLock 源码分析
  • 线程池 ThreadPoolExecutor 类的源码解析
  • 线程池的状态整理
  • 004 DOM01
  • Idea 2018版破解
  • windows如何解除端口占用?
  • Luogu3919 【模板】可持久化数组(主席树)
  • Red Hat开发最新Linux操作系统桌面linux操作系统
  • css核心属性
  • leetcode 4. Median of Two Sorted Arrays
  • vim7用户手册笔记
  • 关于对《上海市人民政府办公厅关于执行〈上海市非营业性客车额度拍卖管理规定〉若干要求的通知》的政策解读...
  • 利用cacti和性能计数器实现自定义远程监控
  • [数据结构]链表的实现在PHP中
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 【面试系列】之二:关于js原型
  • CentOS7 安装JDK
  • const let
  • HTML中设置input等文本框为不可操作
  • Intervention/image 图片处理扩展包的安装和使用
  • javascript数组去重/查找/插入/删除
  • js操作时间(持续更新)
  • Just for fun——迅速写完快速排序
  • laravel with 查询列表限制条数
  • nodejs实现webservice问题总结
  • XForms - 更强大的Form
  • 关于List、List?、ListObject的区别
  • 前端相关框架总和
  • 前端之Sass/Scss实战笔记
  • 前嗅ForeSpider中数据浏览界面介绍
  • 数据仓库的几种建模方法
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 微信小程序实战练习(仿五洲到家微信版)
  • 自动记录MySQL慢查询快照脚本
  • 移动端高清、多屏适配方案
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (补)B+树一些思想
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (图)IntelliTrace Tools 跟踪云端程序
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • *上位机的定义
  • .Net 6.0 处理跨域的方式
  • .Net core 6.0 升8.0
  • .NET delegate 委托 、 Event 事件,接口回调
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET 中的轻量级线程安全
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .NET实现之(自动更新)