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

Java各种锁

目录

一、读写锁(ReentrantReadWriteLock)

二、非公平锁(synchronized/ReentrantLock)

三、可重入锁/递归锁(synchronized/ReentrantLock)

四、自旋锁(spinlock)

五、乐观锁/悲观锁

六、死锁

1、死锁代码

 2、死锁的检测(jps -l 与 jstack 进程号)

七、sychronized-wait-notify 与 lock-await-signal的对比

1、sychronized与lock的对比

2、分组加锁的实例


本文通过学习:周阳老师-尚硅谷Java大厂面试题第二季 总结的锁相关的笔记

一、读写锁(ReentrantReadWriteLock)

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;class MyCache {private volatile Map<String, Object> map = new HashMap<>();//volatile保证可见性private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();public void put(String key, Object value) {rwLock.writeLock().lock();//写锁创建try {System.out.println(Thread.currentThread().getName() + "\t 正在写入:" + key);try {// 模拟网络拥堵,延迟0.3秒TimeUnit.MILLISECONDS.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}map.put(key, value);System.out.println(Thread.currentThread().getName() + "\t 写入完成");} catch (Exception e) {e.printStackTrace();} finally {rwLock.writeLock().unlock();//写锁释放}}public void get(String key) {rwLock.readLock().lock();//读锁创建try {System.out.println(Thread.currentThread().getName() + "\t 正在读取:");try {TimeUnit.MILLISECONDS.sleep(300);//模拟网络拥堵,延迟0.3秒} catch (InterruptedException e) {e.printStackTrace();}Object value = map.get(key);System.out.println(Thread.currentThread().getName() + "\t 读取完成:" + value);} catch (Exception e) {e.printStackTrace();} finally {rwLock.readLock().unlock();//读锁释放}}public void clean() {map.clear();//清空缓存}
}public class ReadWriteLockDemo {public static void main(String[] args) {MyCache myCache = new MyCache();for (int i = 1; i <= 5; i++) {//5个线程写final int tempInt = i;//finalnew Thread(() -> {myCache.put(tempInt + "", tempInt +  "");}, String.valueOf(i)).start();}for (int i = 1; i <= 5; i++) {//5个线程读final int tempInt = i;//finalnew Thread(() -> {myCache.get(tempInt + "");}, String.valueOf(i)).start();}}
}

二、非公平锁(synchronized/ReentrantLock)

定义区别
非公平锁多个线程获取锁的顺序,并不是按照申请锁的顺序,有可能申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转,或者饥饿的线程(也就是某个线程一直得不到锁)比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式
公平锁多个线程按照申请锁的顺序来获取锁,类似于排队买饭,先来后到,先来先服务,就是公平的,也就是队列很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列中的第一个,就占用锁,否者就会加入到等待队列中,以后安装FIFO的规则从队列中取到自己
  • synchronized是非公平锁
  • ReentrantLock默认非公平锁
    • Lock lock = new ReentrantLock(true);//默认false非公平锁,true公平锁

三、可重入锁/递归锁(synchronized/ReentrantLock)

synchronized可重入锁

ReentrantLock可重入锁

class MySynchronized {public synchronized void sendSMS() throws Exception{//发短信System.out.println(Thread.currentThread().getName() + "\t invoked sendSMS()");sendEmail();//同步方法中调用另外一个同步方法}public synchronized void sendEmail() throws Exception{//发邮件System.out.println(Thread.currentThread().getId() + "\t invoked sendEmail()");}
}
public class MyDemo {public static void main(String[] args) {MySynchronized mySynchronized = new MySynchronized();new Thread(() -> {try {mySynchronized.sendSMS();} catch (Exception e) {e.printStackTrace();}}, "t1").start();new Thread(() -> {try {mySynchronized.sendSMS();} catch (Exception e) {e.printStackTrace();}}, "t2").start();}
}
/**
t1  invoked sendSMS()
t1  invoked sendEmail()
t2  invoked sendSMS()
t2  invoked sendEmail()
*/
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class MyReentrantLock implements Runnable{Lock lock = new ReentrantLock();@Overridepublic void run() {method1();}public void method1() {lock.lock();try {System.out.println(Thread.currentThread().getName() + "\t exe method1");method2();} finally {lock.unlock();}}public void method2() {lock.lock();try {System.out.println(Thread.currentThread().getName() + "\t exe method2");} finally {lock.unlock();}}
}
public class ReenterLockDemo {public static void main(String[] args) {MyReentrantLock myReentrantLock = new MyReentrantLock();Thread t1 = new Thread(myReentrantLock, "t1");Thread t2 = new Thread(myReentrantLock, "t2");t1.start();t2.start();}
}
/**
t1  exe method1
t1  exe method2
t2  exe method1
t2  exe method2
*/

四、自旋锁(spinlock)

public class SpinLockDemo {// 现在的泛型装的是Thread,原子引用线程AtomicReference<Thread>  atomicReference = new AtomicReference<>();public void myLock() {//加锁Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName() + "\t come in ");//开始自旋,期望值是null,更新值是当前线程,如果是null,则更新为当前线程,否者自旋while(!atomicReference.compareAndSet(null, thread)) {}}public void myUnLock() {//解锁Thread thread = Thread.currentThread();//自己用完了后,把atomicReference变成nullatomicReference.compareAndSet(thread, null);System.out.println(Thread.currentThread().getName() + "\t invoked myUnlock()");}public static void main(String[] args) {SpinLockDemo spinLockDemo = new SpinLockDemo();new Thread(() -> {spinLockDemo.myLock();//加锁try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}spinLockDemo.myUnLock();//释放锁}, "t1").start();//1秒后,启动t2线程占用锁try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {spinLockDemo.myLock();//加锁spinLockDemo.myUnLock();//释放锁}, "t2").start();}
}
/**
t1   come in
.....五秒后.....
t1   invoked myUnlock()
t2   come in 
t2   invoked myUnlock()
*/

首先输出的是 t1 come in,然后1秒后,t2线程启动,发现锁被t1占有,然后不断执行compareAndSet方法,来进行比较,直到t1释放锁后,也就是5秒后,t2成功获取到锁,然后释放
 

五、乐观锁/悲观锁

1、MybatisPlus使用乐观锁的3步走
step1、在数据库增加version字段,默认为1
step2、在实体类增加对应的字段
    @Version
    private Integer version;
step3、注册乐观锁,在MybatisPlusConfig中配置
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

2、悲观锁

六、死锁

1、死锁代码

import java.util.concurrent.TimeUnit;class HoldLockThread implements Runnable{private String lockA;private String lockB;public HoldLockThread(String lockA, String lockB) {this.lockA = lockA;this.lockB = lockB;}@Overridepublic void run() {synchronized (lockA) {System.out.println(Thread.currentThread().getName() + "\t 自己持有" + lockA + "\t 尝试获取:" + lockB);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockB) {System.out.println(Thread.currentThread().getName() + "\t 自己持有" + lockB + "\t 尝试获取:" + lockA);}}}
}public class DeadLockDemo {public static void main(String[] args) {String lockA = "lockA";String lockB = "lockB";new Thread(new HoldLockThread(lockA, lockB), "t1").start();new Thread(new HoldLockThread(lockB, lockA), "t2").start();}
}
/**
t1   自己持有lockA   尝试获取:lockB
t2   自己持有lockB   尝试获取:lockA
*/

 2、死锁的检测(jps -l 与 jstack 进程号)

step1、jps -l

step2、jstack 7560   #后面参数是jps输出的该类的pid

查看最后一行,我们看到 Found 1 deadlock,即存在一个死锁 

七、sychronized-wait-notify 与 lock-await-signal的对比

sychronized   -     wait         -    notify
lock                -   await         -    signal

1、sychronized与lock的对比

sychronizedlock
1.定义JVM层面的java关键字,底层是通过monitor对象来完成api层面的锁,底层是JUC锁(java.util.concurrent.locks.Lock)
2.使用方法不需要用户去手动释放锁,系统自动释放需要用户去手动释放锁,若没有主动释放锁,就有可能出现死锁的现象,需要lock() 和 unlock() 配置try catch语句来完成
3.等待是否中断不可中断

可中断,可以设置超时方法

  • 设置超时方法,trylock(long timeout, TimeUnit unit)

  • lockInterrupible() 放代码块中,调用interrupt() 方法可以中断

4.加锁是否公平非公平锁

默认非公平锁,构造函数可以传递boolean值,true为公平锁,false为非公平锁

锁绑定多个条件Condition没有,要么随机,要么全部唤醒可以精确唤醒

2、分组加锁的实例

题目:多线程之间按顺序调用,实现 A-> B -> C 三个线程启动,要求如下:
AA打印5次,BB打印10次,CC打印15次
紧接着
AA打印5次,BB打印10次,CC打印15次
..
来10轮

分析:链式唤醒的操作,适合用lock

class ShareResource {private int number = 1;//A=1,B=2,c=3private Lock lock = new ReentrantLock();//可重入锁// 这三个相当于备用钥匙private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();public void print5() {lock.lock();try {//step1、判断while(number != 1) condition1.await();//step2、干活for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "\t " + number + "\t" + i);}// step3、唤醒,通知B线程执行number = 2;condition2.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void print10() {lock.lock();try {//step1、判断while(number != 2) condition2.await();//step2、干活for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "\t " + number + "\t" + i);}//step3、唤醒,通知C线程执行number = 3;condition3.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void print15() {lock.lock();try {//step1、判断while(number != 3) condition3.await();//step2、干活for (int i = 0; i < 15; i++) {System.out.println(Thread.currentThread().getName() + "\t " + number + "\t" + i);}//step3、唤醒,通知A线程执行number = 1;condition1.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}public class SyncAndReentrantLockDemo {public static void main(String[] args) {ShareResource shareResource = new ShareResource();new Thread(() -> {for (int i = 0; i < 10; i++) {shareResource.print5();}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {shareResource.print10();}}, "B").start();new Thread(() -> {for (int i = 0; i < 10; i++) {shareResource.print15();}}, "C").start();}
}

相关文章:

Java各种锁

目录 一、读写锁(ReentrantReadWriteLock) 二、非公平锁(synchronized/ReentrantLock) 三、可重入锁/递归锁(synchronized/ReentrantLock) 四、自旋锁(spinlock) 五、乐观锁/悲观锁 六、死锁 1、死锁代码 2、死锁的检测(jps -l 与 jstack 进程号) 七、sychronized-wait…...

TryHackMe-Tardigrade(应急响应)

Tardigrade 您能否在此 Linux 端点中找到所有基本的持久性机制&#xff1f; 服务器已遭到入侵&#xff0c;安全团队已决定隔离计算机&#xff0c;直到对其进行彻底清理。事件响应团队的初步检查显示&#xff0c;有五个不同的后门。你的工作是在发出信号以使服务器恢复生产之前…...

导出GIS | 将EXCEL表格中坐标导出成GIS格式文件

一 前言 EXCEL是我们日常工作学习数据处理的办公软件&#xff0c;操作易上手&#xff0c;几乎人人都会用。EXCEL表格能够处理各种数据&#xff0c;包括经纬度坐标数据&#xff0c;地址数据等等。 有时因工作需要需将表格中地址数据处理为GIS格式的文件&#xff0c;以便能够将数…...

new set数组对象去重失败

我们知道Set是JS的一个种新的数据结构&#xff0c;和数组类似&#xff0c;和数组不同的是它可以去重&#xff0c;比如存入两个1或两个"123"&#xff0c;只有1条数据会存入成功&#xff0c;但有个特殊情况&#xff0c;如果添加到set的值是引用类型&#xff0c;比如数组…...

Acwing: 一道关于线段树的好题(有助于全面理解线段树)

题目链接&#x1f517;&#xff1a;2643. 序列操作 - AcWing题库 前驱知识&#xff1a;需要理解线段树的结构和程序基本框架、以及懒标记的操作。 题目描述 题目分析 对区间在线进行修改和查询&#xff0c;一般就是用线段树来解决&#xff0c;观察到题目一共有五个操作&…...

DD-1/40 10-40mA型【接地继电器】

系列型号&#xff1a; DD-1/40接地继电器 DD-1/50接地继电器 DD-1/60接地继电器 一、 用途及工作原理 DD-1型接地继电器为瞬时动作的过电流继电器&#xff0c;用作小电流接地电力系统高电压三相交流发电机和电动机的接地零序过电流保护。继电器线圈接零序电流互感器(电缆式、母…...

【女神节】简单使用C/C++和Python嵌套for循环生成一个小爱心

目录 前言实现分析代码实现代码如下效果如下优化效果代码如下效果如下总结尾叙前言 女神节马上到了,有女朋友的小伙伴是不是已经精心准好礼物了呢!对于已婚男士,是不是整愁今天又该送什么礼物呢!说真的,我也整愁着,有什么要推荐么,评论留言下! 实现分析 可以先在纸上或…...

Biome-BGC生态系统模型与Python融合技术实践应用

查看原文>>> Biome-BGC生态系统模型与Python融合技术实践应用 Biome-BGC是利用站点描述数据、气象数据和植被生理生态参数&#xff0c;模拟日尺度碳、水和氮通量的有效模型&#xff0c;其研究的空间尺度可以从点尺度扩展到陆地生态系统。 在Biome-BGC模型中&#xf…...

ESP32 GPIO使用

ESP32 GPIO使用 #define GPIO_OUT_PIN 2 //定义引脚号 #define GPIO_OUTPUT_PIN_SEL (1<<GPIO_OUT_PIN) //定义输出引脚的宏&#xff0c;用来将输出引脚号转换为位掩码void bsp_gpio_init(){gpio_config_t io_conf;io_conf.pin_bit_mask GPIO_OUTPUT_PIN_SE…...

JavaScript 高级4 :正则表达式

JavaScript 高级4 &#xff1a;正则表达式 Date: January 19, 2023 Text: 正则表达式、正则表达式特殊字符、正则表达式中的替换 目标&#xff1a; 能够说出正则表达式的作用 能够写出简单的正则表达式 能够使用正则表达式对表单进行验证 能够使用正则表达式替换内容 正则…...

如何让AI帮你干活-娱乐(3)

背景今天的话题会偏代码技巧一些&#xff0c;对于以前没有接触过代码的朋友或者接触代码开发经验较少的朋友会有些吃力。上篇文章介绍了如何广视角的生成相对稳定的视频。昨天的实现相对简单&#xff0c;主要用的是UI界面来做生成。但是生成的效果其实也显而易见&#xff0c;不…...

webview的工作、内存泄漏、漏洞以及缓存机制原理原理+方案解决

分析一段appium的日志来分析webview的工作原理&#xff0c;文章尾部附有自动化脚本及完整日志&#xff1a; 解析&#xff1a; 获取上下文列表 服务端发送命令adb shell cat /proc/net/unix获取域套接字列表。那什么是域套接字呢&#xff1f; 域套接字&#xff1a;是unix系统里…...

BFD协议原理

BFD协议原理引入背景不使用BFD带来的问题OSPF感知慢VRRP产生次优路径BFD技术简介BFD会话建立方式和检测机制BFD会话建立过程BFD工作流程BFD的单臂回声BFD默认参数以及调整方法总结引入背景 随着网络应用的广泛部署&#xff0c;网络发生中断可能影响业务正常运行并造成重大损失…...

你把骑行当什么? 它就是你需要的

1.骑行是一种有活力的运动&#xff0c;尝试一下你一定会喜欢上它的&#xff01;2.把骑行当作一种娱乐&#xff0c;让自己快乐地体验自然的美&#xff01;3.骑行可以帮助你改变心态&#xff0c;让你的心情变得更加愉悦&#xff01;4.让骑行成为你每天的计划&#xff0c;看看骑行…...

python基础系列 —— 迭代器与内置高阶函数

目录 一、迭代器 1、基本概念 2、如何定义一个迭代器 3、如果判断对象是否是迭代器 4、如何重置迭代器 5、如何调用迭代器 二、高阶函数 1、map函数 2、filter函数 3、reduce函数 4、sorted函数 一、迭代器 1、基本概念 迭代&#xff1a;是一个重复的过程,每次重复…...

MySQL面试题-日志

目录 1.MySQL 中常见的日志有哪些&#xff1f; 2.慢查询日志有什么用&#xff1f; 3.binlog 主要记录了什么&#xff1f; 4.Mysql的binlog有几种录入格式&#xff1f;分别有什么区别&#xff1f; 5.redo log 如何保证事务的持久性&#xff1f; 6.页修改之后为什么不直接刷…...

Android 10.0 去掉Launcher3默认给 icon增加的APK图标白边

1.概述 在10.0的系统产品开发中,Launcher3定制化开发中,发现在给第三方app的icon绘制图标的时候,会有白边第三方app的图标没有完全绘制出来,而系统app不存在这个问题,是完全绘制出来的,所以需要分析图标绘制类来解决这个问题 2.去掉Launcher3默认给 icon增加的APK图标白…...

E900V21C(S905L-armbian)安装armbian-Ubuntu(WiFi)

基本上是s905L芯片的刷机都是如此&#xff0c;包括Q7等 在网上寻找好多的教程关于e900v21c的刷机包和教程都少的可怜&#xff0c;唯一的就是这个&#xff1a;山东联通版创维E900V21C盒子刷入Armbiam并安装宝塔和Docker&#xff0c;但他是不能用WiFi和蓝牙的然后就是寻找s90l的…...

tpc协议的3次握手和4次挥手

建立连接的3次握手过程&#xff1a; A: 我想和你建立连接&#xff0c;你收到我的请求吗&#xff1f;(我想娶你) B: 好的&#xff0c;我收到了你的请求&#xff0c;我们可以建立连接&#xff0c;我同意。(好的,我愿意嫁给你) A: 好的&#xff0c;我收到了你的回应&#xff0c;我…...

YOLOv5害虫识别项目代码打包完整上传Gitee仓库(已开源)以及git上传速率限制踩坑记录

YOLOv5害虫识别项目代码打包完整上传Gitee仓库&#xff08;已开源&#xff09;以及git上传速率限制踩坑记录 ps: ​ 最近很多小伙伴需要这个害虫识别项目的源码&#xff0c;由于文件过大&#xff0c;所以将代码完整上传至gitee&#xff0c;所有文件、教程、论文、以及代码模型…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...