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

ReentrantLock

看了下J.U.C并发包下的ReentrantLock源码,费了不少劲,做个小总结吧,尽量用通俗易懂的语言描述,配上一些图说明。

ReentrantLock介绍

ReentrantLock是基于AbstractQueuedSynchronizer(AQS框架)设计的,类里面有一个私有sync成员属性,其类型为AbstractQueuedSynchronizer;

那么什么是AQS框架呢?AQS是由大神Doug Lea设计的,他写了一篇论文叫《The java.util.concurrent Synchronizer Framework 》,里面详细描述了AQS的设计思想,想看中文翻译的,可以去并发编程网里阅读,链接。

我这里简要说明下,AQS主要是维护了一个int类型的state属性,一个非阻塞、先进先出的线程等待队列;其中state是用volatile修饰的,保证线程之间的可见性,队列的入队和出对操作都是无锁操作,基于自旋锁和CAS实现;另外AQS分为两种模式:独占模式和共享模式,本文讨论的ReentrantLock,主要涉及AQS的独占模式

回过头来说ReentrantLock,其内部有三个内部类Sync、NonfairSync和FairSync,其中NonfairSync和FairSync继承SyncSync继承AbstractQueuedSynchronizer,这三个内部类主要是为了实现父类AbstractQueuedSynchronizer中未实现的tryRelease(int)和tryAcquire(int)方法;

其实ReentrantLock类本身并没有实现什么新功能,仔细观察其下面的方法,发现都是通过调用sync的方法去实现的,如下所示:

    //省略前面部分...
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
    public void unlock() {
        sync.release(1);
    }
    public Condition newCondition() {
        return sync.newCondition();
    }
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
    //省略后面部分...

源码分析

先看一下我们平时都是怎样使用ReentrantLock的,如下代码:

        ReentrantLock lock = new ReentrantLock();
        lock.lock();

        try {
            // do something
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

这里的ReentrantLock是一个非公平独占锁,其保证do something在同一时刻只有一个线程能访问,当有线程正在执行do something里的代码时,其它线程将会等待。

那么,我们就先从lock方法开始,分析ReentrantLock是如何实现非公平独占锁的;

ReentrantLock的lock方法调用的是synclock方法,而sync是在构造方法里初始化的,由于我们未传入参数,默认为NonfairSync类型;

lock方法,调用synclock方法:

    public void lock() {
        sync.lock();
    }

无参构造方法,默认为非公平锁:

    public ReentrantLock() {
        sync = new NonfairSync();
    }

按照执行步骤,转到NonfairSync的lock方法:

 

接着调用:

 

转载于:https://www.cnblogs.com/chenpi/p/5607449.html

相关文章:

  • OSChina 周日乱弹 —— 去应聘男友吧
  • 在网站开发中很有用的8个 jQuery 效果【附源码】
  • 装上这几个 VSCode 插件后,上班划水摸鱼不是梦
  • 三谈属性动画——Keyframe以及ViewPropertyAnimator
  • 湖北分布式智能数据采集方法有哪些?
  • C#用正则表达式一键Unicode转UTF8(解决LitJson中文问题)
  • vue + echarts画圈圈
  • 微软职位内部推荐-SENIOR SDE
  • 23种设计模式之抽象工厂
  • Prototype 原型模式
  • web应用与http协议
  • PDF格式文件如何编辑,怎样修改PDF背景颜色
  • js confirm函数
  • Bootstrap学习:Bootstrap 环境安装
  • Dubbo Mesh 在闲鱼生产环境中的落地实践
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 2019.2.20 c++ 知识梳理
  • CAP理论的例子讲解
  • ComponentOne 2017 V2版本正式发布
  • CSS居中完全指南——构建CSS居中决策树
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • HashMap剖析之内部结构
  • java8 Stream Pipelines 浅析
  • JS基础之数据类型、对象、原型、原型链、继承
  • k8s 面向应用开发者的基础命令
  • nfs客户端进程变D,延伸linux的lock
  • October CMS - 快速入门 9 Images And Galleries
  • SQLServer插入数据
  • Vue.js 移动端适配之 vw 解决方案
  • yii2中session跨域名的问题
  • 分布式任务队列Celery
  • 将 Measurements 和 Units 应用到物理学
  • 一道闭包题引发的思考
  • 译自由幺半群
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • #1015 : KMP算法
  • #Ubuntu(修改root信息)
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (SpringBoot)第二章:Spring创建和使用
  • (阿里云万网)-域名注册购买实名流程
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (十)c52学习之旅-定时器实验
  • (十六)一篇文章学会Java的常用API
  • (算法)Game
  • (五)关系数据库标准语言SQL
  • (循环依赖问题)学习spring的第九天
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .NET 中创建支持集合初始化器的类型
  • .NET企业级应用架构设计系列之技术选型
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945
  • [2019.3.20]BZOJ4573 [Zjoi2016]大森林