【JUC系列第五篇】-ReentrantLock锁原理解读
作者 : 毕来生
锁状态转换
Lock分类
Jdk1.5以后帮助我们提供了线程同步机制,通过显示定义同步锁来实现对象之间的同步。还是Doug Lea这个家伙写的。相信读过源码的人在很多地方都可以看到这个家伙。
Lock可以显示的进行加锁,解锁。但是每次只能有一个线程对Lock对象加锁
Lock实现结构如下图所示:
按照使用的常用度,分别标注了(1),(2),(3)。接下来我们就主要学习一下ReentrantLock的使用
可重入锁
ReentrantLock实现的前提就是AbstractQueuedSynchronizer,简称AQS.。核心方法内部实现均在AQS中,后续我们在详细解读AQS相关知识点以及使用场景。我们先来看一段伪代码用以表述可重入锁的使用情况。接下来我们来详细分析获取锁以及释放锁内部实现到底做了什么事情。
package org.bilaisheng.juc; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author: bilaisheng * @Wechat: 878799579 * @Date: 2019/1/3 22:55 * @Todo: 伪代码仅演示使用 * @Version : JDK11 , IDEA2018 */ public class ReentrantLockTest { public static void main(String[] args) { Lock lock = new ReentrantLock(); // 获取锁 lock.lock(); // access the resource protected by this lock // do something // 释放锁 lock.unlock(); } }
Sync对象剖析
/** Synchronizer providing all implementation mechanics */ private final Sync sync; /** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */ abstract static class Sync extends AbstractQueuedSynchronizer { // xxxx }
他会根据传入构造方法的布尔类型参数实例化出Sync的实现类FairSync和NoFairSync。
- FairSync: 公平的Sync
- NoFairSync : 不公平的Sync
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
ReentrantLock.lock()实现原理
我们用的比较多的ReentrantLock是非公平锁,我们来用一张图来分析一下看看它是如何实现的。
上图就做了两件事情:
1、设置AbstractQueuedSynchronizer的state为1
2、设置AbstractOwnableSynchronizer的thread为当前线程
线程A正在执行中,status = 1。
线程B尝试利用CAS去判断state是不是0,是0就设置为1,当然这一步操作肯定是失败的,因为线程A已经将state设置成了1,所以此时肯定是失败的。
失败了之后进入FIFO等待队列。等待重新尝试
/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ @ReservedStackAccess final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
因为在AbstractQueuedSynchronizer中state是用volatile关键字声明的,故可以在线程间可见
/** * The synchronization state. */ private volatile int state;
再次判断一下能否持有锁(可能线程A同步代码执行得比较快,已经释放了锁),不可以就返回false。
根据上方代码可以看出同一个锁最多能重入Integer.MAX_VALUE次,也就是2147483647。
ReentrantLock.unLock()实现原理
此处较为简单。附上调用关系链路
// 步骤一 public void unlock() { sync.release(1); } // 步骤二 : AbstractQueuedSynchronizer public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } //步骤二 : ReentrantLock @ReservedStackAccess protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
当一条线程对同一个ReentrantLock全部解锁之后,AQS的state就是0了,AbstractOwnableSynchronizer的exclusiveOwnerThread将被设置为null,这样就表示没有线程占有锁,方法返回true。
喜欢就关注我吧
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
【JUC系列第四篇】-CountDownLatch使用场景分析
作者 : 毕来生 前言 在 java.util.concurrent 包中提供了多种并发容器类来改进同步容器 的性能。今天我们来聊一聊CountDownLatch 的使用场景。看看它到底是怎么玩耍的。 CountDownLatch 是干什么的? CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作 之前,它允许一个或多个线程一直等待。 CountDownLatch原理 CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。 使用场景 在某些业务情况下,要求我们等某个条件或者任务完成后才可以继续处理后续任务。同时在线程完成时也会触发一定事件。方便业务继续向下执行。这个时候我们的CountDownLatch就隆重登场啦。常用核心方法为 /** * 递减计数器的计数,如果计数达到0,则释放所有等待的线程。 * 如果当前计数大于0,则将计数减少。 * 如果新的计数为0,会重启所有...
- 下一篇
GPS定位系统源码只有这种才是最适合做二次开发的
GPS定位系统是一个泛概念,有很多种类,比如公交车,物流车,渣土车,船运车辆,宠物定位等等监控管理系统都属于GPS定位系统里面的一个分支!每个分支的应用场景都不一样,宠物定位的GPS定位系统主要侧重宠物这一块,比如功能就会包括宠物年龄,种类,疫苗情况,售后宠物店等等细节!渣土车就是载重重量,运输趟数统计,司机联系方式,车辆保养,保险等等功能!这些都叫GPS定位系统,那么这些GPS定位系统的源代码适合做二次开发吗?显然是不适合的! 什么东西做什么事情都是设计好的,你要拉货运输显然要买个卡车,你经常跑高速就可以买个轿车;没人会买个轿车去干拉货的事情;GPS定位系统也是这样,如果要做二次开发,当然就要选择专为二次开发而设计的GPS定位系统了;这样才会更节省开发成本,让开发更简单便捷! GPSBD就是专为二次开发而设计的GPS定位系统,系统集成实时定位,轨迹回放,电子围栏,统计报表,指令下发,报警通知等功能于一体,开发者只需根据对应的应用场景完善业务层即可投入使用;GPSBD系统集成市面上主流的几十种车机通信协议,开发者无需对接任何协议,即可直接接入智能定位硬件终端! GPSBD专注位置服务!...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- 2048小游戏-低调大师作品
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Red5直播服务器,属于Java语言的直播服务器
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7