java Lock锁的使用

Lock接口

public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock();
Condition newCondition();
}

这 5 种方法分别是 lock()、tryLock()、tryLock(long time, TimeUnit unit) 和 lockInterruptibly()、 unlock()。

lock()

在线程获取锁的时如果锁被其它的线程获取了,就会进行等待,lock加锁和释放锁都必须以代码的形式写出来,是由我们自己释放锁。要有trycatch语 句,在try中获取资源,如果出现异常在catch中捕获,然后释放锁。
伪代码使用如下:

Lock lock = ...; lock.lock();
try{
}finally{ lock.unlock();
}

一定不要忘记在finally语句中释放锁,否则是非常危险的锁会得不到释放,一旦陷入死锁就 会造成很大的隐患。

tryLock()

它可以尝试获取当前的锁,如果其他线程没有被占用,就能获取成功,返回true,反之亦然。
为代码如下:

Lock lock = ...; 
if(lock.tryLock()) { 
try{//业务逻辑
}finally{ lock.unlock();
}
}else {}

有了这个强大的 tryLock()方法我们便可以解决死锁问题
如下面的例子:
死锁是多线程编程中一种比较复杂的问题,而使用锁可以一定程度上避免死锁的发生。下面是一个简单的Java Lock锁解决死锁的例子,使用ReentrantLocktryLock方法来避免死锁。
考虑两个资源ResourceAResourceB,两个线程分别需要访问这两个资源。如果线程1先获取ResourceA,然后尝试获取ResourceB,而线程2先获取ResourceB,然后尝试获取ResourceA,就可能发生死锁。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class DeadlockExample {private static class SharedResource {final Lock lock = new ReentrantLock();}private static class MyThread extends Thread {private final SharedResource resource1;private final SharedResource resource2;public MyThread(String name, SharedResource resource1, SharedResource resource2) {super(name);this.resource1 = resource1;this.resource2 = resource2;}@Overridepublic void run() {try {// 尝试获取第一个资源resource1.lock.lock();System.out.println(getName() + " acquired lock on " + resource1);// 等待一段时间模拟处理业务逻辑Thread.sleep(100);// 尝试获取第二个资源if (resource2.lock.tryLock()) {try {System.out.println(getName() + " acquired lock on " + resource2);// 执行业务逻辑} finally {resource2.lock.unlock();System.out.println(getName() + " released lock on " + resource2);}} else {System.out.println(getName() + " couldn't acquire lock on " + resource2 + ". Releasing lock on " + resource1);}} catch (InterruptedException e) {e.printStackTrace();} finally {resource1.lock.unlock();System.out.println(getName() + " released lock on " + resource1);}}}public static void main(String[] args) {SharedResource resourceA = new SharedResource();SharedResource resourceB = new SharedResource();// 创建两个线程,分别尝试获取不同的资源MyThread thread1 = new MyThread("Thread-1", resourceA, resourceB);MyThread thread2 = new MyThread("Thread-2", resourceB, resourceA);// 启动两个线程thread1.start();thread2.start();}
}

运行结果:

Thread-1 acquired lock on SharedResource@hash1
Thread-1 acquired lock on SharedResource@hash2
Thread-2 couldn't acquire lock on SharedResource@hash1. Releasing lock on SharedResource@hash2
Thread-1 released lock on SharedResource@hash2
Thread-1 released lock on SharedResource@hash1
Thread-2 acquired lock on SharedResource@hash2
Thread-2 acquired lock on SharedResource@hash1
Thread-2 released lock on SharedResource@hash1
Thread-2 released lock on SharedResource@hash2

这个输出说明线程1首先获取resource1的锁,然后等待一段时间,尝试获取resource2的锁。由于线程2已经获取了resource2的锁,线程1无法立即获取resource2的锁,因此释放了resource1的锁。随后,线程2成功获取了resource1的锁,完成了整个流程。

tryLock(long time, TimeUnit unit)

该方法可以设置超时时间,如果拿不到锁等待超了设置的时间后,线程就会放弃获取这把 锁。在等待的时间也可以中断线程,避免死锁的发生。
如下面的例子:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;public class TryLockExample {private static class SharedResource {final Lock lock = new ReentrantLock();}private static class MyThread extends Thread {private final SharedResource resource;public MyThread(String name, SharedResource resource) {super(name);this.resource = resource;}@Overridepublic void run() {try {if (resource.lock.tryLock(500, TimeUnit.MILLISECONDS)) {try {System.out.println(getName() + " acquired lock on " + resource);// 执行业务逻辑} finally {resource.lock.unlock();System.out.println(getName() + " released lock on " + resource);}} else {System.out.println(getName() + " couldn't acquire lock on " + resource + " within 500 milliseconds");

运行结果:

Thread-1 acquired lock on SharedResource@hash1
Thread-2 couldn't acquire lock on SharedResource@hash1 within 500 milliseconds
Thread-1 released lock on SharedResource@hash1

Thread-1首先获取了锁,而 Thread-2 在500毫秒内无法获取到锁,因此放弃锁的获取。
之后Thread-1释放了锁。

lockInterruptibly()

此方法的作用是获取锁,如果这个锁可以获得,那么该方法就会立刻返回。如果获取不到 被其他线程占用了,就会一直等待。
使用为代码:

public void lockInterruptibly() { try {
lock.lockInterruptibly();
try { System.out.println(“操作资源”); } finally {
lock.unlock();
}
} catch (InterruptedException e) { e.printStackTrace();
}
}

unlock()

就是解锁。
对于ReentrantLock执行此方法,内部就会把锁,持有锁的计数器减去1,当减去1为0时 候。此锁就被释放了。

总结

  1. 引入Lock接口: Lock 接口提供了比传统的synchronized关键字更为灵活和可扩展的锁定机制。在 java.util.concurrent.locks 包中定义了多个实现了 Lock 接口的类,其中最常用的是 ReentrantLock
  2. 获取锁: 使用 lock() 方法来获取锁。这一步类似于使用synchronized关键字进行同步,但提供了更灵活的控制。
lock.lock();
try {// 执行需要同步的代码块
} finally {lock.unlock();
}
  1. 释放锁:finally 块中使用 unlock() 方法释放锁,确保锁的释放,避免死锁和其他并发问题。
  2. 可中断性: 使用 lockInterruptibly() 方法可实现可中断的锁获取。在等待锁的过程中,线程可以被中断,以避免长时间的阻塞。
try {lock.lockInterruptibly(); // 可中断地获取锁// 执行需要同步的代码块
} catch (InterruptedException e) {// 处理中断异常
} finally {lock.unlock();
}
  1. 超时获取锁: 使用 tryLock(long time, TimeUnit unit) 方法,可以尝试在指定时间内获取锁。如果在指定时间内无法获取到锁,线程可以选择放弃或进行其他处理。
if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {try {// 执行需要同步的代码块} finally {lock.unlock();}
} else {// 未能在指定时间内获取到锁
}

总的来说,Lock 提供了更多的控制和灵活性,适用于更复杂的并发场景。在使用时,需要注意合理释放锁,避免死锁,并根据具体需求选择合适的锁实现和锁策略。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络虚拟化场景下网络包的发送过程

网络虚拟化有和存储虚拟化类似的地方,例如,它们都是基于 virtio 的,因而在看网络虚拟化的过程中,会看到和存储虚拟化很像的数据结构和原理。但是,网络虚拟化也有自己的特殊性。例如,存储虚拟化是将宿主机上…

python绘制箱线图boxplot——用于多组数据的比较, 异常值检测

python绘制箱线图boxplot——用于多组数据的比较, 异常值检测 介绍箱线图方法简介箱线图适用范围seaborn.boxplot箱图外观设置异常值marker形状、填充色、轮廓设置完整代码 如下matplotlib.pyplot常见参数介绍 本文系统详解利用python中seaborn.boxplot绘制箱图boxplot。seab…

跟着chatgpt一起学|2.clickhouse入门(1)

上周我们一起学习了spark,这周让chatgpt帮我们规划下clickhouse的学习路径吧! 目录 ​编辑 1.了解Clickhouse的基本概念 1.1 Clickhouse是什么? 1.2 ClickHouse的特点和优势 1.3 Clickhouse的基本架构与组件 1.了解Clickhouse的基本概念…

链式队列的结构设计及基本操作的实现(初始化,入队,出队,获取元素个数,判空,清空,销毁)

目录 一.链式队列的设计思想 二.链式队列的结构设计 三.链式队列的实现 四.链式队列的总结 一.链式队列的设计思想 首先一定要理解设计的初衷,就是队头队尾的位置要满足怎么快怎么设计.那么分析如下: 最终我们敲定了入队,出队的时间复杂度都为O(1)的一种设计,也就是第四种设…

LDO版图后仿性能下降

记录一下LDO,debug 问题1: LDO后仿输出电压下降,前仿输出1.8V,后仿却输出只有1.58V。 解决办法: 功率管的走线问题,布线太少,存在IR drop问题。功率管的面积比较大,需要横竖都多…

面试--各种场景问题总结

1.在开发过程中,你是如何保证机票系统的正常运行的? 用户、测试、监控和日志、安全措施、数据备份、系统设计、需求分析 2.在机票系统开发过程中,你最有成就的事情,为什么? 用户体验感、高可用和稳定性、客户满意度、系…

什么情况下会导致索引失效

程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一份大厂面试资料《史上最全大厂面试题》,Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …

SSM实战项目,基于Spring+SpringMVC+mybatis实现的人事管理系统源码+数据库+使用说明

SSM实战项目:人事管理系统(蓝色版) 一、员工管理系统项目说明: 该项目主要是完成SpringSpringMVCmybatis的完整整合,功能实现比较单一,就是一个完成增删改查的小项目! 完整代码下载地址SSM实…

Python zip函数及用法与lambda表达式及用法

Python zip函数及用法 zip() 函数可以把两个列表“压缩”成一个 zip 对象(可迭代对象),这样就可以使用一个循环并行遍历两个列表。为了测试 zip() 函数的功能,我们可以先在交互式解释器中“试验”一下该函数的功能。 >>&g…

软件工程期末复习(1)

学习资料 软件工程知识点总结_嘤桃子的博客-CSDN博客 软件工程学习笔记_软件工程导论第六版张海藩pdf-CSDN博客 【软件工程】软件工程期末试卷习题课讲解!!_哔哩哔哩_bilibili 【拯救者】软件工程速成(期末考研复试软考)均适用. 支持4K_哔哩哔哩_bil…

redis单线程为什么这么快

redis单线程为什么这么快 redis是使用的单线程来进行操作的,因为所有的数据都是在内存中的,内存操作特别快。而且单线程避免了多线程切换性能损耗问题 单线程如何处理并发客户端连接? redis利用epoll来实现IO多路复用,将连接信息和…

【halcon】C# halcon 内存暴增

1 读取图片需要及时手动释放 一个6M的图片通过halcon进行加载&#xff0c;大约会消耗200M的内存&#xff0c;如果等待GC回收&#xff0c;而你又在不停的读取图片&#xff0c;你的内存占用&#xff0c;将在短时间内飙升。 2 halcon控件显示图片需要清空。 /// <summary>…

dp-带权活动选择

Description 给定n个活动&#xff0c;活动ai表示为一个三元组(si,fi,vi)&#xff0c;其中si表示活动开始时间&#xff0c;fi表示活动的结束时间&#xff0c;vi表示活动的权重, si<fi。带权活动选择问题是选择一些活动&#xff0c;使得任意被选择的两个活动ai和aj执行时间互不…

dataframe.values.tolist() 举例说明

dataframe.values.tolist() 是将 Pandas DataFrame 中的数据转换为嵌套的 Python 列表&#xff08;list of lists&#xff09;。这将返回一个包含 DataFrame 所有行和列的嵌套列表。以下是一个简单的例子&#xff1a; 假设有如下的 DataFrame&#xff1a; import pandas as p…

【Unity记录】EDM4U(External Dependency Manager)使用说明

GitHub - googlesamples/unity-jar-resolver: Unity plugin which resolves Android & iOS dependencies and performs version management 引入谷歌包时发现有这个玩意&#xff0c;主要用途是自动搜索工程内任意文件夹下的Editor/*Dependencies.xml文件 <dependencie…

基于eBPF检测内核模块安装行为

本文实现一个简单的示例&#xff0c;展示了如何编写一个eBPF程序来检测未知内核模块的安装行为。 首先&#xff0c;请确保系统已安装eBPF工具链。然后&#xff0c;创建一个名为unknown_module_detection.c的C文件&#xff0c;并使用以下代码填充内容&#xff1a; c #include …

D*算法学习

系列文章目录 A*算法学习-CSDN博客 弗洛伊德算法&#xff08;Floyd&#xff09;和路径平滑弗洛伊德算法&#xff08;Smooth Floyd&#xff09;学习-CSDN博客 目录 系列文章目录 前言 一、D*算法是什么&#xff1f; 二、D* 算法是对 A* 算法的改进 三、增量搜索是什么 总…

梯度爆炸梯度消失

梯度消失和梯度爆炸是深度学习中常见的问题&#xff0c;与神经网络的训练相关。这两个问题都涉及到梯度在反向传播过程中的传递。 梯度消失&#xff08;Gradient Vanishing&#xff09;&#xff1a; 当神经网络较深时&#xff0c;反向传播过程中梯度可能逐层减小&#xff0c;最…

【FMC139】青翼科技基于VITA57.1标准的4路500MSPS/1GSPS/1.25GSPS采样率14位AD采集FMC子卡模块

板卡概述 FMC139是一款基于VITA57.1标准规范的JESD204B接口FMC子卡模块&#xff0c;该模块可以实现4路14-bit、500MSPS/1GSPS ADC采集功能。该板卡ADC器件采用ADI公司的AD9680芯片,全功率-3dB模拟输入带宽可达2GHz。该ADC与FPGA的主机接口通过8通道的高速串行GTX收发器进行互联…

Python模块与Linux stat 命令:双剑合璧的文件系统探索

简介&#xff1a;在Linux和Unix-like系统中&#xff0c;stat命令用于获取文件或目录的详细属性信息&#xff0c;包括但不限于大小、所有权、权限和时间戳。同样&#xff0c;在Python编程中&#xff0c;我们也有多个模块&#xff08;例如os、pathlib等&#xff09;提供了与stat类…