前言

相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么实现的。如果真是这样,而且你有兴趣了解,今天我将带领你轻松的学习下java中非常重要,也非常基础的可重入锁-ReentrantLock的实现机制。


听故事把知识掌握了

在一个村子里面,有一口井水,水质非常的好,村民们都想打井里的水。这井只有一口,村里的人那么多,所以得出个打水的规则才行。村长绞尽脑汁,最终想出了一个比较合理的方案,咱们来仔细的看看聪明的村长大人的智慧。

井边安排一个看井人,维护打水的秩序。

打水时,以家庭为单位,哪个家庭任何人先到井边,就可以先打水,而且如果一个家庭占到了打水权,其家人这时候过来打水不用排队。而那些没有抢占到打水权的人,一个一个挨着在井边排成一队,先到的排在前面。打水示意图如下 :

是不是感觉很和谐,如果打水的人打完了,他会跟看井人报告,看井人会让第二个人接着打水。这样大家总都能够打到水。是不是看起来挺公平的,先到的人先打水,当然不是绝对公平的,自己看看下面这个场景 :

看着,一个有娃的父亲正在打水,他的娃也到井边了,所以女凭父贵直接排到最前面打水,羡煞旁人了。 
以上这个故事模型就是所谓的公平锁模型,当一个人想到井边打水,而现在打水的人又不是自家人,这时候就得乖乖在队列后面排队。

事情总不是那么一帆风顺的,总会有些人想走捷径,话说看井人年纪大了,有时候,眼力不是很好,这时候,人们开始打起了新主意。新来打水的人,他们看到有人排队打水的时候,他们不会那么乖巧的就排到最后面去排队,反之,他们会看看现在有没有人正在打水,如果有人在打水,没辄了,只好排到队列最后面,但如果这时候前面打水的人刚刚打完水,正在交接中,排在队头的人还没有完成交接工作,这时候,新来的人可以尝试抢打水权,如果抢到了,呵呵,其他人也只能睁一只眼闭一只眼,因为大家都默认这个规则了。这就是所谓的非公平锁模型。新来的人不一定总得乖乖排队,这也就造成了原来队列中排队的人可能要等很久很久。

java可重入锁-ReentrantLock实现细节

ReentrantLock支持两种获取锁的方式,一种是公平模型,一种是非公平模型。在继续之前,咱们先把故事元素转换为程序元素。

咱们先来说说公平锁模型:

初始化时, state=0,表示无人抢占了打水权。这时候,村民A来打水(A线程请求锁),占了打水权,把state+1,如下所示:

线程A取得了锁,把 state原子性+1,这时候state被改为1,A线程继续执行其他任务,然后来了村民B也想打水(线程B请求锁),线程B无法获取锁,生成节点进行排队,如下图所示:

初始化的时候,会生成一个空的头节点,然后才是B线程节点,这时候,如果线程A又请求锁,是否需要排队?答案当然是否定的,否则就直接死锁了。当A再次请求锁,就相当于是打水期间,同一家人也来打水了,是有特权的,这时候的状态如下图所示:

到了这里,相信大家应该明白了什么是可重入锁了吧。就是一个线程在获取了锁之后,再次去获取了同一个锁,这时候仅仅是把状态值进行累加。如果线程A释放了一次锁,就成这样了:

仅仅是把状态值减了,只有线程A把此锁全部释放了,状态值减到0了,其他线程才有机会获取锁。当A把锁完全释放后,state恢复为0,然后会通知队列唤醒B线程节点,使B可以再次竞争锁。当然,如果B线程后面还有C线程,C线程继续休眠,除非B执行完了,通知了C线程。注意,当一个线程节点被唤醒然后取得了锁,对应节点会从队列中删除。

非公平锁模型

如果你已经明白了前面讲的公平锁模型,那么非公平锁模型也就非常容易理解了。当线程A执行完之后,要唤醒线程B是需要时间的,而且线程B醒来后还要再次竞争锁,所以如果在切换过程当中,来了一个线程C,那么线程C是有可能获取到锁的,如果C获取到了锁,B就只能继续乖乖休眠了。这里就不再画图说明了。

其它知识点

java5中添加了一个并发包, java.util.concurrent,里面提供了各种并发的工具类,通过此工具包,可以在java当中实现功能非常强大的多线程并发操作。对于每个java攻城狮,我觉得非常有必要了解这个包的功能。虽然做不到一步到位,但慢慢虚心学习,沉下心来,总能慢慢领悟到java多线程编程的精华。

结束语

可重入锁的实现会涉及到CAS,AQS,java内存可见性(volatile)等知识,为了避免大家直接被代码搞晕,故而想以最简单的方式把可重入锁进行抽象,讲明白其中的实现原理,这样看起源码也有个借鉴的思路,希望本篇能够帮助到你们。

原文:http://blog.csdn.net/yanyan19880509/article/details/52345422

转载于:https://www.cnblogs.com/azhqiang/p/8556078.html

轻松学习java可重入锁(ReentrantLock)的实现原理相关推荐

  1. java中的账户冻结原理_java可重入锁(ReentrantLock)的实现原理

    前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...

  2. java多线程---重入锁ReentrantLock

    1.定义 重入锁ReentrantLock,支持重入的锁,表示一个线程对资源的重复加锁. 2.底层实现 每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获 ...

  3. Java多线程——重入锁ReentrantLock源码阅读

    上一章<AQS源码阅读>讲了AQS框架,这次讲讲它的应用类(注意不是子类实现,待会细讲). ReentrantLock,顾名思义重入锁,但什么是重入,这个锁到底是怎样的,我们来看看类的注解 ...

  4. Java 重入锁 ReentrantLock 原理分析

    1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...

  5. 并发编程-19AQS同步组件之重入锁ReentrantLock、 读写锁ReentrantReadWriteLock、Condition

    文章目录 J.U.C脑图 ReentrantLock概述 ReentrantLock 常用方法 synchronized 和 ReentrantLock的比较 ReentrantLock示例 读写锁R ...

  6. Java 可重入锁内存可见性分析

    转载自 深度好文 | Java 可重入锁内存可见性分析 一个习以为常的细节 之前在做 ReentrantLock 相关的试验,试验本身很简单,和本文相关的简化版如下:(提示:以下代码均可左右滑动) p ...

  7. java 可重入锁 clh_Java并发编程系列-(4) 显式锁与AQS

    4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...

  8. java可重入锁与不可重入锁

    所谓重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的. synchronized 和   ReentrantLock 都是可重入锁. 可重 ...

  9. Java 可重入锁 不可重入锁

    文章目录 Java 可重入锁 & 不可重入锁 概述 论证synchronized是可重入锁: 论证Lock是可重入锁: 自定义不可重入锁: Java 可重入锁 & 不可重入锁 概述 可 ...

  10. 重入锁ReentrantLock详解

    重入锁ReentrantLock,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁.除此之外,该锁的还支持获取锁时的公平和非公平性选择. 在AQS实现中,当一个线程调用Mute ...

最新文章

  1. Docker安装Nextcloud
  2. 一个handle使用更新线程的实例
  3. Meteor工作目录的划分
  4. 浅谈JQuery中$('.classname').get(0); $('.classname').eq(0); $('.classname')[0]三者的区别
  5. python preference界面设置_偏好设置如何更改Preference的样式
  6. mysql分区功能详细介绍,以及实例
  7. 【转】浅析动态代理类实现过程
  8. 在页面制作过程中需要注意事项
  9. 《四世同堂》金句摘抄(十六)
  10. spring aop实现原理_Spring 异步实现原理与实战分享
  11. 使用MQTT与函数计算做热力图的实践
  12. Redis bind用法
  13. MySQL开发医药管理系统_医药管理系统struts+hibernat+mySql,内含需求分析,详细设计文档...
  14. linux 设置多网段ip 地址,举例说明Linux不同网段访问的设置办法
  15. 阿里云OSS 使用内网地址上传文件
  16. CSDN刷访问量专用博客
  17. 换硬币 (20 分)
  18. java手机飞信_手机飞信JAVA通用版 手机飞信2011通用版
  19. 为什么visio输出图片俩边有留白_Microsoft Office Visio导出图片添加边界的操作教程...
  20. web工程师的自我修养

热门文章

  1. spring5.0学习笔记3
  2. pymysql操作数据库
  3. re.sub对多处字符串进行替换
  4. numpy.zeros(np.zeros)
  5. 机器学习高质量数据集大合辑
  6. SQLServer数据库写操作报错String or binary data would be truncated问题解决
  7. c++ vector向量
  8. 服务器下 读取springboot application配置文件_一文读懂 Spring Boot 配置文件 application.properties !...
  9. python编码转换语句_将“ yield from”语句转换为Python 2.7代码
  10. “十四五”国家重点研发计划“区块链”重点专项 2022年(附pdf下载地址)