java并发之加锁

java并发编程(三)客户端加锁与组合 客户端加锁: java为线程安全提供了一套安全的集合类操作 在java.util.Collections中,在多线程下能 安全的CRUD,但是应该注意,仅是对几何类进行同步,下面看一个实例。 若没有则添加实例: public class ListHelper { public List list = Collections.synchronizedList(new ArrayLi 阅读详情

这段时间有一个需要是要“开宝箱”,涉及到一个事务中有多个数据库表要同步更新,初始阶段没有加锁导致一系列并发问题(当大脑沉浸在业务逻辑上的思考时候很容易忽略,原谅我的狡辩),期间遇到一些“灵异现象”,但最后在高手的指点下渐渐明白了一些以前留在大脑却没有理解深刻的概念,比如分布式锁、悲观锁、乐观锁等。下面按照我解决问题的先后顺序和问题发酵的流程,一些罗列遇到的各种坑。

ReentranLock

第一步就是想在代码中加入同步锁,结构先是如下:

这里写图片描述

在整个黑色框代表的事务(逻辑包括从数据库中获取宝箱中的物品,按照权重随机函数选择其中一个物品,然后更新该物品为已使用)中,一开始把同步锁加在1,即锁住整个事务,进行junit测试并发,并发问题马上解决。初始成功后,为了优化下性能,我把同步锁换成在2的位置,此时并发问题再次到来——并发10个线程开启宝箱,可是最后数据库里消耗的物品记录并不是10个,而是3-4个,查看日志有好几条物品记录被重复消费。此时我的思维凝固在1和2之间的区域的差集中努力寻找bug,可是这段代码除了查询还是查询,不可能会存在并发问题。经过一番思考后发现其实错误不在这里。2位置将并发的线程都挡在这里,只有一条线程进入,当第一条线程完成并释放锁后,还未来得及提交事务commit,第二个进入的线程就已经获得锁并执行完了代码,如此反复出现了并发问题。了解到原因后我又把同步锁切换到位置1,此时思考即便放在1,只要速度过快,还是有可能会有并发问题,而且生成的服务是分布式部署的,这样只能控制单台机器,多台机器下还是可能会选择到同一个物品,此时萌发的第二个想法是进行分布式锁。

分布式锁

简单的将上述的同步锁换成分布式锁,从逻辑上就不会再有并发问题了,但是同时又引入了一个问题,这个开宝箱的逻辑,在分布式环境下,同个时间只能由一台机器中的一个线程去执行,这除了发挥不了分布式服务的优势,还白白把多线程的给浪费了。从这里就可以感悟,分布式锁不适合这个场景,应该废弃。

mysql锁

上次的锁机制虽然能解决问题,但是性能大打折扣,应该选择粒度更小的锁,于是把锁机制从代码转移到了数据库。mysql的锁分为乐观锁和悲观锁。这两个概念相信很多人听过,但是真正应用的可能只有部分。

悲观锁

这个名字取得好,悲观锁就是在获取数据的时候(select)永远认为这些选择的记录都会被其他线程所修改,所以select 的时候总会加入排它锁,其他线程要想获取更新这些记录就要阻塞等待。在mysql中select记录最后最加for update,就可以使用排它锁将其锁住。
mysql的排它锁是利用索引键字段来控制的,如果select语句中where id=1,即明确主键,那么将会只锁住这一条记录。如果是select * from tb where age=10 limit 1;,其中age是索引,但不是唯一索引,mysql 会将所有age=1的记录都锁住。如果where中的条件不是任何索引,将会进行全表锁。所以一般要进行for update 的语句where筛选属性一般要加锁。

乐观锁

乐观锁认为大部分情况下获取数据是不会有并发问题,等到有问题在进行解决。所以乐观锁的select并不会加上for update。而一般在乐观锁的表中有一个version字段用于表明当前数据记录的版本号,我们在select 的时候已经获取出来version=1,而当要进行update的时候在where条件中加入version=1,如果有数据返回,证明记录没有被修改可以更新,如果获取不到,则本次更新失败,可以进行重试机制。乐观锁用与读多写少的场景,而乐观锁则相反,乐观锁广泛应用在nosql中

另外关于mysql在innodb存储引擎下关于查询的条件是否使用行锁还是表锁,请参考这边文章
http://blog.youkuaiyun.com/claram/article/details/54023216

Java高并发编程实战10,Java文件加锁机制 Java提供了文件加锁的机制,可以使用java.nio.channels.FileLock类来实现文件锁定。 阅读详情

相关推荐

Java单服务加锁工具类

Java加锁工具类。用于普通加锁。 可以用到的场景有: 1、多线程对同一数据进行处理时,通过此类进行简单加锁。 2、想保证后台同时,只有一个线程在处理某事情时。 3、更新数据库信息时。

Java笔记(锁)

当程序中可能出现并发的情况时,就需要保证在并发情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和他单独操作时的结果是一样的,这就叫做。没有做好并发控制,就可能导致脏读、幻读和不可重复读等问题。实现的主要手段分为和。

KeePCoding 1489

C# 进程间 双内存共享 高帧率图像传输

演示了两个进程之间通过 双内存共享 的方式, 来实时处理图像,并以高帧率(40~60FPS)传输的基本示例。 进程间内存共享的优点:高性能、低延迟、资源效率高、简单可靠。 适用场景:实时图像处理、大数据传输、多进程协作、实时监控系统,等等。

qianqiansd 1996

java高并发之锁

并发锁是一种同步机制,用于控制多个线程或进程对共享资源的访问,以防止数据竞争和保证数据一致性。在多线程或多进程环境中,当多个执行单元同时尝试修改同一资源时,如果没有适当的控制,可能会导致不一致或不可预测的结果。锁提供了一种机制来确保在任何时刻只有一个执行单元可以访问特定的资源。互斥锁(Mutex)互斥锁是最基本的锁类型,用于保护临界区,确保同一时间只有一个线程可以访问共享资源。当一个线程获得互斥锁时,其他线程必须等待,直到锁被释放。读写锁(Read-Write Lock)

qq_36070104的博客 1358

基于CANoe的Basic Diagnostics ECU (UDS)

基于CANoe的Basic Diagnostics ECU (UDS)

farmer00的博客 9153

Nacos启动报错No DataSource set?5分钟搞定standalone模式配置

本文针对Nacos启动时常见的“No DataSource set”报错,深入解析了其根源在于默认集群模式与外部数据库依赖。提供了两种快速解决方案:通过命令行参数“-m standalone”启动,或直接修改启动脚本配置文件,从而在5分钟内以单机模式成功启动Nacos,无需配置MySQL数据库。

weixin_29234509的博客 465

Java并发——锁()

锁

编程就像打游戏,编出一个项目就打过了一个BOSS 910

使用在UE5中使用AirSim插件Eigen库头文件引用报错,出现报错的解决方式

如图所示,用红线圈出的两条头文件引用会报错,提示无法找到他们,但是可以发现的是,他们的路径书写是没有问题的。在终端中运行时候,会出现如下的报错。

GFCLJY的博客 1006

并发控制——封锁、活锁和死锁

封锁 封锁就是事务T在对某个数据对象(表、记录等)操作之前,先向系统发出请求,对其枷锁 加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象 封锁是实现并发控制的一个非常重要的技术 封锁类型 基本封锁类型 排它锁(eXclusive lock,简称X锁) 共享锁(Share lock,简称S锁) 排它锁 排它锁又称为写锁、X锁 若事务T1对数据对象A加上X锁,则只允许T1读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T1释放A上的

MrLiuの甜蜜小屋 4760

vue3 - 超详细 cropper.js 实现图片(头像)裁剪效果功能,在vue3中上传图像后按比例进行图片的裁剪及实时预览,Element / Ant Desi(详细示例源码,一键复制开箱即用!)

vue3图片裁剪及实时预览,vue3 vue-cropper,vue3头像裁剪,vue3 el-upload+vue-cropper 图像图片头像裁剪上传,vue3怎么进行图片的裁剪,vue3使用vue-cropper图片裁剪,vue3项目如何实现头像图片裁剪上传功能,vue3网站pc怎么将上传的图片按比例进行裁剪,vue3+element plus实现图片上传按尺寸大小裁剪,vue3中图片上传使用cropperjs 头像裁剪,vue3中图片上传使用cropperjs 头像裁剪,vue3好用的图片裁剪插件组

✅ 精选推荐文章 4506

YOLOv11 损失函数解析

YOLOv11 在 YOLO 系列的持续演进中,通过 ​多模态损失协同优化、动态任务感知机制 和 ​超轻量化设计,实现了检测精度与推理效率的再突破。其损失函数设计融合了前沿的几何建模、分布学习与自监督技术,显著提升了复杂场景下的鲁棒性。

浩瀚之水的专栏 6702

并发编程并发安全性之Lock锁及原理分析

lock锁主要分为两部分锁的抢占和锁的释放抢占锁:是在释放锁和抢占锁的临界区 区分公平锁和非公平锁,非公平锁是在当前线程释放锁的瞬间刚来进来一个新的线程,则无需排队可以直接抢占锁,如果没有抢占到,则加入到AQS队列中进行阻塞等待。而公平锁的体现是加入到AQS队列中的阻塞线程,当释放锁后,只能按照先后顺序去抢占锁。释放锁:释放锁的过程就是把独占锁的线程设为null,状态state恢复为无锁状态,并且去AQS队列中唤醒第一个处于等待的线程节点。

still_five_Days的博客 1371

基于深度学习的三维重建算法——详解与实现

随着深度学习技术的迅猛发展,基于深度学习的三维重建算法在最近几年取得了显著的进展。而基于深度学习的三维重建算法通过利用深度神经网络,能够从大规模数据中学习到更准确、鲁棒的三维结构表示。本文综述了基于深度学习的三维重建算法,并给出了相应的源代码。随着深度学习技术的不断发展,我们相信基于深度学习的三维重建算法将会在未来得到更广泛的应用。实验结果表明,基于深度学习的三维重建算法在准确性和鲁棒性方面取得了显著的提升。以上是关于基于深度学习的三维重建算法的详细介绍与实现,希望对您有所帮助。

CyberGenius的博客 1228

JAVA并发之加锁导致的活跃性问题

首先提及一下前置知识: 1.JAVA并发之基础概念 2.JAVA并发之进程VS线程 3.JAVA并发之多线程引发的问题剖析及如何保证线程安全 ​ 在前三章我们讨论了多线程并发的优点以及如何加锁来处理并发带来的安全性问题 ​ 但是加锁也为我们带来了诸多问题 如:死锁,活锁,线程饥饿等问题 这一章我我们主要处理锁带来的问题. 首先就是最出名的死锁 1.死锁(Deadlock) 什么是死锁 死锁是当线程进入无限期等待状态时发生的情况,因为所请求的锁被另一个线程持有,而另一个

srs1995的博客 527

【软件系统架构】系列五:TCP/IP 协议栈

TCP/IP协议栈是现代网络通信的核心框架,采用分层架构设计,包含应用层、传输层、网络层和网络接口层四层结构。应用层提供HTTP、FTP等用户服务接口;传输层通过TCP/UDP实现端到端通信;网络层负责IP寻址和路由选择;网络接口层处理物理数据传输。数据在传输过程中经历层层封装,从应用层报文最终转换为物理层的比特流。该协议栈通过三次握手建立连接、数据传输、四次挥手断开连接的流程,确保可靠通信。作为互联网的基础,TCP/IP协议栈具有跨平台、标准化和可扩展的特点,广泛应用于各类网络设备和嵌入式系统中。

moton2017的博客 2163

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java 并发笔记(一):synchronized 对 Integer 加锁的注意事项

最近在学习 Java 并发的相关知识,发现 synchronized 锁对 Integer 等基本类型的包装类没有效果,示例如下: public class AccountingSyncBad implements Runnable { static volatile Integer i = 0; public static void increase() { s...

LeeFire的博客 2357

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【Java并发处理代码规范】之并发修改同一记录时的加锁策略

该规范指出在Java编程中,并发修改同一记录时,需要加锁来避免更新丢失。可以在应用层加锁、缓存层加锁,或者在数据库层使用乐观锁,使用version作为更新依据。

wang2leee的博客 836

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java 并发 Map 的 get 方法要加锁么

对于来说,读操作(如get)不需要加锁,而写操作会在内部自动处理锁定。对于通过包装的Map,所有读写操作都需要显式加锁。选择哪种方式取决于你的具体需求和场景。如果性能是一个关键因素,那么通常是更好的选择。

程序员猫爪 544

java 加锁_JAVA并发之加锁导致的活跃性问题

首先提及一下前置知识: 1.JAVA并发之基础概念 2.JAVA并发之进程VS线程 3.JAVA并发之多线程引发的问题剖析及如何保证线程安全 ​ 在前三章我们讨论了多线程并发的优点以及如何加锁来处理并发带来的安全性问题 ​ 但是加锁也为我们带来了诸多问题 如:死锁,活锁,线程饥饿等问题 这一章我我们主要处理锁带来的问题. 首先就是最出名的死锁 1.死锁(Deadl...

weixin_39907939的博客 99

java高并发加锁异常实战案例1

高并发、加锁、多线程

sunsiny 1612

java 客户端加锁_java并发编程(三)客户端加锁与组合

客户端加锁:java为线程安全提供了一套安全的集合类操作 在java.util.Collections中,在多线程下能 安全的CRUD,但是应该注意,仅是对几何类进行同步,下面看一个实例。若没有则添加实例:public class ListHelper {public List list = Collections.synchronizedList(new ArrayList());public ...

weixin_40004051的博客 324

java锁方法无效_java并发编程之 service层处理并发事务加锁可能会无效

java并发编程之 service层处理并发事务加锁可能会无效最近注意到一个问题--在service层处理要多次操作数据库事务时往往要@Transactional事务注解,这个时候就要注意了,如果是在并发情况下,而且在service层加了锁,这个时候并不能保证这个事务操作的原子性,并会出现我们意向不到的问题。本人做了一个测试,service层有一个方法,方法中获取数据库中的一个int值,然后将这个...

weixin_39688687的博客 882

Java并发编程:解锁并发编程中的加锁技巧

无锁编程是一种不使用传统锁机制来实现线程同步的编程范式。它依赖于原子操作来确保线程安全,这样的操作可以直接由现代处理器提供支持。

逆流的小鱼 1406

对java并发编程实战中ConcurrentHashMap不能加锁实现独占访问的理解

java并发编程实战中5.2.2节写到由于ConcurrentHashMap不能被加锁来执行独占式访问,因此我们无法使用客户端加锁来创建新的原子操作。 一开始无法理解这句话的描述,因为如果有一个ConcurrentHashMap对象,在所有使用这个对象的地方都对这个对象客户端加锁,那么也能保证这个对象复合操作的原子性;后来才明白他想说的其实是即使使用客户端加锁,也存在无法保证Concurrent...

打码的土豆 539
上一篇: tomcat的运作和性能调优杂谈
下一篇: java并发之死锁
@云师兄
博客等级 码龄10年 10粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值