ReentrantLock详解

介绍

  • 它是可重入锁的互斥锁,又被称为“独占锁”。
  • 它在同一时间点只能被一个线程锁持有;可重入表示,ReentrantLock锁可被同一个线程多次获取。
  • 它是通过一个FIFO的等待队列来管理获取该锁所有线程的。在“公平锁”的机制下,线程依次排队获取锁;而“非公平锁”在锁是可获取状态时,不管自己是不是在队列的开头都会获取锁。

ReentrantLock构造方法

/**
* 默认创建非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* fair为true表示是公平锁,
fair为false表示是非公平锁
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

主要方法

获取和释放锁

  1. lock()
  • 阻塞式地获取锁。如果锁已经被其他线程持有,当前线程将被阻塞,直到获取到锁。
  1. tryLock()
  • 非阻塞式地尝试获取锁。成功获取锁返回 true,失败返回 false
  1. lockInterruptibly()
  • 类似于 lock(),但支持对获取锁的过程中被中断。
  1. tryLock(long timeout, TimeUnit unit)
  • 在指定的时间范围内尝试获取锁,超时后返回结果。
  1. unlock()
  • 释放锁。必须在当前线程持有锁的情况下调用,否则会抛出 IllegalMonitorStateException

查询锁状态

  1. isHeldByCurrentThread()
  • 查询当前线程是否持有锁。
  1. getHoldCount()
  • 查询当前线程持有锁的次数。
  1. getQueueLength()
  • 查询正在等待获取锁的线程数。
  1. hasQueuedThreads()
  • 查询是否有线程在等待获取锁。

其他方法

  1. isFair()
  • 查询锁是否是公平锁。
  1. isLocked()
  • 查询锁是否被任意线程持有。
  1. newCondition()
  • 返回与此锁关联的新 Condition 实例,用于实现更灵活的线程间通信。

示例

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Example {
    private Lock lock = new ReentrantLock();

    public void performTask() {
        lock.lock(); // 获取锁
        try {
            // 执行需要同步的任务
        } finally {
            lock.unlock(); // 释放锁
        }
    }
}

在使用 ReentrantLock 时,通常将 lockunlock 放在 try-finally 块中,以确保在发生异常时也能正确释放锁。

源码分析

lock方法分析

以下是lock方法的大体逻辑uml流程图:
在这里插入图片描述

以下是代码调用顺序流程图:

在这里插入图片描述

tryLock()方法分析

ReentrantLock tryLock方法是一个可重入的互斥锁,它用于尝试获取独占锁,如果锁已经被其他线程持有,那么当前线程会立即返回false,不会进入等待队列。它的基本逻辑是:

  • 调用nonfairTryAcquire方法,传入参数1,表示获取一个锁。
  • 调用tryAcquire方法,尝试通过CAS操作更新state变量,表示锁的状态和重入次数。
  • 如果state为0,说明锁未被占用,那么尝试将state设置为1,如果成功则设置当前线程为独占锁的线程,并返回true。
  • 如果state不为0,说明锁已经被占用,那么判断持有锁的线程是否为当前线程,如果是则累加state值,表示重入锁的次数,并返回true。
  • 如果以上两种情况都不满足,那么返回false,表示获取锁失败。

如下图所示:
在这里插入图片描述

时序流程图,如下所示:
在这里插入图片描述

unlock()方法分析

ReentrantLock unlock方法是一个可重入的互斥锁,它用于释放独占锁,如果锁已经被当前线程重入多次,那么只有当state变为0时,才会真正释放锁,并唤醒等待队列中的下一个线程。它的基本逻辑是:

  • 调用sync.release方法,传入参数1,表示释放一个锁。
  • 调用tryRelease方法,判断当前线程是否为独占锁的线程,如果不是则抛出IllegalMonitorStateException异常。
  • 如果是,则减少state值,表示减少重入锁的次数。
  • 如果state为0,说明锁已经完全释放,那么清空独占锁的线程,并返回true。
  • 如果state不为0,说明锁还未完全释放,那么返回false。

如下UML流程图所示:

在这里插入图片描述

下面的是时序图:

在这里插入图片描述

lockInterruptibly()方法分析

ReentrantLock lockInterruptibly方法是一个可重入的互斥锁,它用于获取独占锁,如果锁已经被其他线程持有,那么当前线程会进入等待队列,直到获取到锁或者被中断。它的基本逻辑是:

  • 调用acquireInterruptibly方法,传入参数1,表示获取一个锁。
  • 调用tryAcquire方法,尝试通过CAS操作更新state变量,表示锁的状态和重入次数。
  • 如果state为0,说明锁未被占用,那么尝试将state设置为1,如果成功则设置当前线程为独占锁的线程,并返回true。
  • 如果state不为0,说明锁已经被占用,那么判断持有锁的线程是否为当前线程,如果是则累加state值,表示重入锁的次数,并返回true。
  • 如果以上两种情况都不满足,那么返回false,表示获取锁失败。
  • 如果tryAcquire方法返回false,那么调用addWaiter方法,将当前线程封装为一个节点,加入到等待队列的尾部。
  • 然后调用acquireQueued方法,使当前线程在等待队列中自旋,直到获取到锁或者被中断。

我为您生成了一个UML流程图,如下所示:
在这里插入图片描述

时序图如下:

在这里插入图片描述

tryLock(long timeout, TimeUnit unit)分析

ReentrantLock tryLock(long timeout, TimeUnit unit)方法是一个可重入的互斥锁,它用于尝试获取独占锁,如果锁已经被其他线程持有,那么当前线程会在指定的时间内等待,如果在期间获取到锁,就返回true,否则返回false。它的基本逻辑是:

  • 调用tryAcquireNanos方法,传入参数1和单位转换后的纳秒数,表示获取一个锁并设置超时时间。
  • 调用tryAcquire方法,尝试通过CAS操作更新state变量,表示锁的状态和重入次数。
  • 如果state为0,说明锁未被占用,那么尝试将state设置为1,如果成功则设置当前线程为独占锁的线程,并返回true。
  • 如果state不为0,说明锁已经被占用,那么判断持有锁的线程是否为当前线程,如果是则累加state值,表示重入锁的次数,并返回true。
  • 如果以上两种情况都不满足,那么返回false,表示获取锁失败。
  • 如果tryAcquire方法返回false,那么调用addWaiter方法,将当前线程封装为一个节点,加入到等待队列的尾部。
  • 然后调用doAcquireNanos方法,使当前线程在等待队列中自旋,直到获取到锁或者被中断或者超时。

如下所示:
在这里插入图片描述

时序图如下所示:
在这里插入图片描述

总结

通过源码流程分析让我们更加深入了解了ReentrantLock锁的实现流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/239350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL笔记-第08章_聚合函数

视频链接:【MySQL数据库入门到大牛,mysql安装到优化,百科全书级,全网天花板】 文章目录 第08章_聚合函数1. 聚合函数介绍1.1 AVG和SUM函数1.2 MIN和MAX函数1.3 COUNT函数 2. GROUP BY2.1 基本使用2.2 使用多个列分组2.3 GROUP BY中…

理解排序算法:冒泡排序、选择排序与归并排序

简介: 在计算机科学中,排序算法是基础且重要的概念。本文将介绍三种常见的排序方法:冒泡排序、选择排序和归并排序。我们将探讨它们的工作原理、特点和适用场景,以帮助读者更好地理解和选择合适的排序方法。 冒泡排序 冒泡排序是…

cs环境部署

配置搭建cs工具 两种方式 cs工具 》狐狸工具箱,微信上搜索 或者cs - OneDrive (sharepoint.com)提取密码www.ddosi.org 需要云服务器(个人猜测如果是靶场的话,可以采用一台所有主机都能访问的主机作为服务端配置) 非docker方式搭建 将c…

ue5材质预览界面ue 变黑

发现在5.2和5.1上都有这个bug 原因是开了ray tracing引起的,这个bug真是长时间存在,类似的bug还包括草地上奇怪的影子和地形上的影子等等 解决方法也很简单,就是关闭光追(不是…… 就是关闭预览,在材质界面preview sc…

10基于matlab的悬臂梁四节点/八节点四边形单元有限元编程(平面单元)

悬臂梁,有限元编程。基于matlab的悬臂梁四节点/八节点四边形单元有限元编程(平面单元),程序有详细注解,可根据需要更改参数,包括长度、截面宽度和高度、密度、泊松比、均布力、集中力、单元数量等。需要就拍…

【算法】递归、搜索与回溯算法

文章目录 一. 名词解释1. 递归1.1 什么是递归?1.2 为什么会用到递归?1.3 如何理解递归?1.4 如何写好一个递归? 2. 遍历和搜索3. 回溯和剪枝 二. 递归系列专题1. 汉诺塔问题2. 合并两个有序链表3. 反转链表4. 两两交换链表中的节点…

关于Anaconda的安装和环境部署(此章专为新手制定)

目录 Anaconda简介 一、软件下载(地址👇) 2:点击下载 3:版本选择: 4:Anaconda的安装包就下载完成了 2:恭喜你,看到这里已经完成安装了 三、部署环境 1&#xff1…

什么是 AWS IAM?如何使用 IAM 数据库身份验证连接到 Amazon RDS(上)

驾驭云服务的安全环境可能很复杂,但 AWS IAM 为安全访问管理提供了强大的框架。在本文中,我们将探讨什么是 AWS Identity and Access Management (IAM) 以及它如何增强安全性。我们还将提供有关使用 IAM 连接到 Amazon Relational Database Service (RDS…

C++类模板分文件编写

问题: 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到 解决: 解决方式最常用的:将声明和实现写到同一个文件,并更改后缀名为.hpp,hpp是约定的名称,并不是强制的

Windows/Linux混合刻录后,Windows显示空白盘解决思路

概述 因为工作环境问题,需要在Windows和Linux之间来回光盘刻录,没有多余光盘的时候经常多次使用,同一光盘在Windows刻录文件到Linux,然后从Linux刻录文件到Windows,Windows用“类似U盘”格式化的光盘,在Wi…

洛谷 P8802 [蓝桥杯 2022 国 B] 出差

文章目录 [蓝桥杯 2022 国 B] 出差题目链接题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 思路解析CODE [蓝桥杯 2022 国 B] 出差 题目链接 https://www.luogu.com.cn/problem/P8802 题目描述 A \mathrm{A} A 国有 N N N 个城市,编号为 1 … N …

三天精通Selenium Web 自动化 - Selenium(Java)环境搭建

1 下载JDK JDK下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 2 安装和配置JDK 安装目录尽量不要有空格 D:\Java\jdk1.8.0_91; D:\Java\jre8设置环境变量: “我的电脑”->右键->“属性”->…

LeetCode刷题日志-73矩阵置零

思路一: 用一个同样大小的矩阵记录0的位置,然后遍历矩阵置0, 空间复杂度为O(mn) class Solution {public void setZeroes(int[][] matrix) {int [][] matrix_new new int[matrix.length][matrix[0].length];for(int …

postgresql自带指令命令系列三

目录 简介 bin目录 28.pg_verifybackup 29.pg_waldump 30.postgres 31.postmaster -> postgres 32.psql 33.reindexdb 34.vacuumdb 35.vacuumlo 总结: 简介 在安装postgresql数据库的时候会需要设置一个关于postgresql数据库的PATH变量 export PATH/…

1845_emacs中一个中文乱码问题分析解决

Grey 全部学习内容汇总:GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 1845_emacs中一个中文乱码问题分析解决 曾经有一次放弃过我自己的emacs配置,一个原因就是中文的支持。感觉我的配置跟其他人的配置显得有些…

优雅玩转实验室服务器(一)登录服务器

这篇文章更加偏向于使用python程序进行研究的朋友们 原料 Windows主机实验室Linux服务器(可以访问互联网)一点点耐心 step.0 windows terminal is all you need 别跟我说什么putty,什么winscp,我就是单推Win11自带的软件——win…

deepface:实现人脸的识别和分析

deepface介绍 deepface能够实现的功能 人脸检测:deepface 可以在图像中检测出人脸的位置,为后续的人脸识别任务提供基础。 人脸对齐:为了提高识别准确性,deepface 会将检测到的人脸进行对齐操作,消除姿态、光照和表…

Python 进阶(十六):二进制和ASCII码的转换(binascii 模块)

大家好,我是水滴~~ 本文详细介绍了Python中的binascii模块及其使用方法。通过binascii模块,我们可以方便地进行二进制和ASCII字符串之间的转换操作。文章中包含大量的示例代码,希望能够帮助新手同学快速入门。 《Python入门核心技术》专栏总…

【unity】【WebRTC】从0开始创建一个Unity远程媒体流app-设置输入设备

【项目源码】 包括本篇需要的脚本都打包在项目源码中,可以通过下面链接下载: 【背景】 目前我们能投射到远端浏览器(或者任何其它Peer)的媒体流只有默认的MainCamera画面,其实我们还可以通过配置输入来传输操作输入信息,比如键鼠等。 【追加input processing组件】 …

在AWS Lambda中使用FFmpeg处理m3u8视频流

大纲 1 部署有FFmpeg功能的Lambda环境1.1 部署层1.2 部署代码1.2.1 FFmpeg指令1.2.2 代码 2 配置Lambda角色权限2.1 选择角色类型2.2 设置权限2.3 保存角色2.4 绑定角色 参考文献 在直播里领域,我们经常需要对视频流进行处理。FFmpeg则是该领域中处理的利器。这篇文…