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

ReentranLock(可重入锁)

一、ReentranLock

ReentranLock属于JUC并发工具包下的类,相当于 synchronized具备如下特点

● 可中断
● 可以设置超时时间
● 可以设置为公平锁(防止线程出现饥饿的情况)
● 支持多个条件变量

与 synchronized一样,都支持可重入

基本语法(synchronized在关键字级别保护临界区, reentrantLock是在对象的级别来保护临界区)

// 获取锁
reentrantLock.lock();
try {// 临界区
} finally {// 释放锁(无论是否出现异常,均会将锁释放)reentrantLock.unlock();
}

lock()与unlock()是成对出现的

1.1 可重入

可重入是指同一个线程对象如果首次获得这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁
如果是不可重入锁,那么第二次获得锁时,自身也会被锁挡住

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;@Slf4j(topic = "c.Test")
public class Test {// 创建锁重入对象private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {// 加锁lock.lock();try {log.debug("enter  main");m1();} finally {// 解锁lock.unlock();}}public static void m1() {// 加锁lock.lock();try {log.debug("enter  m1");m2();} finally {// 解锁lock.unlock();}}public static void m2() {// 加锁lock.lock();try {log.debug("enter  m2");} finally {// 解锁lock.unlock();}}
}

运行结果:(锁重入成功)

在这里插入图片描述

1.2 可打断——lockInterruptibly

在等待锁的过程中其他线程可以用interruput()方法终止等待

import cn.itcast.n2.util.Sleeper;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;@Slf4j(topic = "c.Test")
public class Test {// 创建锁重入对象private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args)  {Thread t1=new Thread(()->{try {// 尝试获取锁,但可以被打断(如果没有别的线程竞争锁,此方法就会获取lock对象上的锁)/*若有竞争进入阻塞队列等待*/log.debug("尝试获得锁");lock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();log.debug("没有获取锁,返回");return;}try {log.debug("获取到锁");}finally {// 将锁释放掉lock.unlock();}},"t1");// 主线程先对其进行加锁后,t1线程才启动lock.lock();t1.start();// 主线程睡眠1s后打断t1Sleeper.sleep(1);t1.interrupt();}
}

运行结果:(成功打断t1线程)

1.3 锁超时

锁超时:在获取锁的过程中,如果其他线程持有锁一直未释放,去尝试获取锁的线程也不会死等,而是等待一段时间,若这段时间超过对方仍未释放锁,则放弃等待,获取锁失败

可打断属于一种被动的避免无限等待(死等)方式;而锁超时以主动的方式避免死等

1、无其他线程竞争锁:

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;@Slf4j(topic = "c.Test")
public class Test {// 创建锁重入对象private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {Thread t1 = new Thread(() -> {log.debug("尝试获得锁");// 尝试获取锁,返回值为布尔型  【成功:获取锁   失败:不可获得锁,不会进入阻塞队列等待】if (!lock.tryLock()) {           //失败则立刻返回(没有任何等待时间)log.debug("获取锁失败");    // falsereturn;}try {// 执行临界区代码log.debug("成功获取锁");} finally {lock.unlock();     // 释放锁}});}
}

运行结果:
在这里插入图片描述

2、存在其他线程竞争(立刻结束):

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;@Slf4j(topic = "c.Test")
public class Test {// 创建锁重入对象private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {Thread t1 = new Thread(() -> {log.debug("尝试获得锁");// 尝试获取锁,返回值为布尔型  【成功:获取锁   失败:不可获得锁,不会进入阻塞队列等待】if (!lock.tryLock()) {log.debug("获取锁失败");    // falsereturn;}try {// 执行临界区代码log.debug("成功获取锁");} finally {lock.unlock();     // 释放锁}});// 主线程先对lock对象加锁lock.lock();log.debug("成功获取锁");t1.start();}
}

运行结果:
在这里插入图片描述

3、存在其他线程竞争(等待一段时间):尝试等待1s,1s内若主线程还未释放锁再结束
在这里插入图片描述

哲学家就餐问题便可以使用tryLock()解决

1.4 公平锁

ReentrantLock 默认是不公平的。当一个线程持有锁,其他线程就会进入阻塞队列等待,当锁的持有者释放锁时,阻塞队列中等待的线程会一拥而上,谁先争抢到锁谁便是Owner,而不会按进入阻塞队列的先后顺序先来先得

(通过查看源码发现其构造方法中有一个带boolean类型参数的方法,其参数fair默认为false,可以修改其布尔值保证其公平性)公平锁一般没有必要,会降低并发度

二、ReentranLock条件变量

2.1 简介

条件变量

synchronized 中也有条件变量,就是我们讲原理时那个 waitSet 休息室,当条件不满足时进入 waitSet 等待

ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比

● synchronized 是那些不满足条件的线程都在一间休息室等消息
● 而 ReentrantLock 支持多间休息室,有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤

使用要点:
● await 前需要获得锁
● await 执行后,会释放锁,进入 conditionObject 等待
● await 的线程被唤醒(或打断、或超时)取重新竞争 lock 锁
● 竞争 lock 锁成功后,从 await 后继续执行

使用例子:

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import static cn.itcast.n2.util.Sleeper.sleep;@Slf4j(topic = "c.Test24")
public class Test24 {static final Object room = new Object();static boolean hasCigarette = false;static boolean hasTakeout = false;static ReentrantLock ROOM = new ReentrantLock();// 等待烟的休息室(创建一个新的条件变量)static Condition waitCigaretteSet = ROOM.newCondition();// 等外卖的休息室(创建一个新的条件变量)static Condition waitTakeoutSet = ROOM.newCondition();public static void main(String[] args) {new Thread(() -> {// 尝试获取ReentrantLockROOM.lock();try {log.debug("有烟没?[{}]", hasCigarette);while (!hasCigarette) {log.debug("没烟,先歇会!");try {// 进入等烟休息室等待waitCigaretteSet.await();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("可以开始干活了");} finally {// 解锁ROOM.unlock();}}, "小南").start();new Thread(() -> {ROOM.lock();try {log.debug("外卖送到没?[{}]", hasTakeout);while (!hasTakeout) {log.debug("没外卖,先歇会!");try {waitTakeoutSet.await();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("可以开始干活了");} finally {ROOM.unlock();}}, "小女").start();// 送外卖线程sleep(1);new Thread(() -> {ROOM.lock();try {hasTakeout = true;// 唤醒线程waitTakeoutSet.signal();} finally {ROOM.unlock();}}, "送外卖的").start();// 送烟线程sleep(1);new Thread(() -> {ROOM.lock();try {hasCigarette = true;// 唤醒线程waitCigaretteSet.signal();} finally {ROOM.unlock();}}, "送烟的").start();}
}

运行结果:
在这里插入图片描述

相关文章:

ReentranLock(可重入锁)

一、ReentranLock ReentranLock属于JUC并发工具包下的类,相当于 synchronized具备如下特点 ● 可中断 ● 可以设置超时时间 ● 可以设置为公平锁(防止线程出现饥饿的情况) ● 支持多个条件变量 与 synchronized一样,都支持可重…...

Kafka 入门 (一)

Kafka 入门(一) Apache Kafka起源于LinkedIn,后来于2011年成为开源Apache项目,然后于2012年成为First-class Apache项目。Kafka是用Scala和Java编写的。 Apache Kafka是基于发布订阅的容错消息系统。 它是快速,可扩展…...

linux内核开发入门二(内核KO模块介绍、开发流程以及注意事项)

linux内核开发入门二(内核KO模块介绍、开发流程以及注意事项) 一、什么是内核模块 内核模块:ko模块(Kernel Object Module)是Linux内核中的可加载模块,它可以动态地向内核添加功能。在运行时,可…...

设计模式(十七)----行为型模式之模板方法模式

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为&…...

【嵌入式Linux内核驱动】01_内核模块

内核模块 宏内核&微内核 微内核就是内核中的一部分功能放到应用层 内核小,精简,可扩展性好,安全性好 相互之间通信损耗多 内核模块 Linux是宏内核操作系统的典型代表,所有内核功能都整体编译到一起,优点是效…...

Spring——数据源对象管理和Spring加载properties文件

前面一直都是在管理自己内部创建的对象&#xff0c;这个是管理外部的对象。 这里先使用阿里巴巴的druid来演示。需要在pom.xml中添加如下的依赖 <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1…...

Zeek安装、使用与压力测试

Zeek安装与压力测试Zeek安装、简单使用与压力测试环境Zeek安装zeek简单运行安装PF_RING修改Zeek配置文件&#xff0c;使用PF_RING&#xff0c;实现集群流量压力测试查看zeek日志Zeek安装、简单使用与压力测试 科研需要&#xff0c;涉及到Zeek的安装、使用和重放流量压力测试评…...

【javaEE初阶】第三节.多线程 (进阶篇 ) 死锁

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、"死锁"出现的典型场景二、产生 "死锁" 的必要条件 三、解决 "死锁" 问题的办法 总结前言 今天对于多线程进阶的学习&#…...

基于密集连接的轻量级卷积神经网络,用于使用边云架构的露天煤矿服务识别

遥感是快速检测非法采矿行为的重要技术工具。由于露天煤矿的复杂性&#xff0c;目前关于露天煤矿自动开采的研究较少。基于卷积神经网络和Dense Block&#xff0c;我们提出了一种用于从Sentinel-2遥感图像中提取露天煤矿区域的轻量级密集连接网络-AD-Net&#xff0c;并构建了三…...

无刷高速风筒方案介绍--【PCBA方案】

疫情三年过去&#xff0c;春节后&#xff0c;一个新的开始&#xff0c;大家满怀希望畅谈今年好气象。 三年来一波一波的封城、隔离、核酸&#xff0c;经济压抑到了无以复加的地步&#xff0c;也导致了诸多社会问题的出现。消费力被磨平&#xff0c;人们小心翼翼的生活。 常跟…...

花括号展开II[栈模拟dfs]

栈模拟dfs前言一、花括号展开II二、栈模拟dfs总结参考资料前言 递归调用&#xff0c;代码非常的简洁。但是可以通过显式栈来模拟栈中的内容&#xff0c;锻炼自己的代码能力&#xff0c;清楚知道栈帧中需要的内容。 一、花括号展开II 二、栈模拟dfs 每碰到一个左括号&#xf…...

神经网络分类任务(手写数字识别)

1.Mnist分类任务 网络基本构建与训练方法&#xff0c;常用函数解析 torch.nn.functional模块 nn.Module模块 学习方法&#xff1a;边用边查&#xff0c;多打印&#xff0c;duogua 使用jupyter的优点&#xff0c;可以打印出每一个步骤。 2.读取数据集 自动下载 %matplotl…...

FCN网络(Fully Convolutional Networks)

首个端到端的针对像素级预测的全卷积网络 原理&#xff1a;将图片进行多次卷积下采样得到chanel为21的特征层&#xff0c;再经过上采样得到和原图一样大的图片&#xff0c;最后经过softmax得到类别概率值 将全连接层全部变成卷积层&#xff1a;通常的图像分类网络最后几层是全…...

随想录二刷Day15——二叉树

文章目录二叉树2. 递归遍历二叉树3. 二叉树的迭代遍历4. 二叉树的统一迭代法二叉树 2. 递归遍历二叉树 144. 二叉树的前序遍历 class Solution { public:vector<int> preorderTraversal(TreeNode* root) {vector<int> result;preorder(root, result);return res…...

docker-compose部署kafka服务时如何同时允许内外网访问?

背景 最近在学习kafka相关知识&#xff0c;需要搭建自己的kafka环境。综合考虑后决定使用docker-compose来管理维护这个环境。 docker-compose.yml Bitnami的yml文件就很不错&#xff0c;这里直接拿来用了。 version: "2"services:zookeeper:image: docker.io/bi…...

数据结构刷题(二十):17电话号码的字母组合、39组合总和、40组合总和II

一、电话号码的字母组合题目链接思路&#xff1a;回溯三部曲。确定回溯函数参数&#xff1a;题目中给的 digits&#xff0c;还要有一个参数就是int型的index&#xff08;记录遍历第几个数字&#xff0c;就是用来遍历digits的&#xff0c;同时也代表了递归的深度&#xff09;&am…...

Java面试总结(五)

sleep() 方法和 wait() 方法对比 相同点 两者都可以暂停线程的执行&#xff1b;两者都可以响应中断。 不同点 sleep()方法不会释放锁&#xff0c;wait()方法会释放锁&#xff1b; sleep()方法主要用于暂停线程的执行&#xff0c;wait()方法主要用于线程之间的交互/通信&…...

三维人脸实践:基于Face3D的渲染、生成与重构 <二>

face3d: Python tools for processing 3D face git code: https://github.com/yfeng95/face3d paper list: PaperWithCode 3DMM方法&#xff0c;基于平均人脸模型&#xff0c;可广泛用于基于关键点的人脸生成、位姿检测以及渲染等&#xff0c;能够快速实现人脸建模与渲染。推…...

在linux上部署Java项目

在Linux部署Java环境 要是想要部署java web程序,首先要配置环境 jdk tomcat mysql 安装jdk 推荐的方法是使用yum直接安装openjdk(开源的,与官方的jdk功能差不多),目前使用的最多的就是jdk8系列 yum list | grep jdk 在源上搜索所有关于jdk的文件 devel表示development的意思…...

线性表的接口

线性表的实现方式 顺序表 顺序表是一种线性表的实现方式&#xff0c;它是用一组地址连续的存储单元依次存储线性表中的数据元素&#xff0c;使得逻辑上相邻的元素在物理上也相邻⁴。顺序表可以用数组来实现&#xff0c;它的优点是可以快速定位第几个元素&#xff0c;但是缺点…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...