Java常用锁的使用

Java 锁系列 一 概述 Java 提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文旨在对锁相关源码(本文中的源码来自 JDK 8)、使用场景进行举例,为读者介绍主流锁的知识点,以及不同的锁的适用场景。 Java 中往往是按照是否含有某一特性来定义锁,我们通过特性将锁进行分组归类,再使用对比的方式进行介绍,帮助大家更快捷的理解相关知识。下面给出本文内容的总体分类目录: 二 乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度。在 Java 和数据库中都有 阅读详情

Java常用锁的使用

详见:https://zhuanlan.zhihu.com/p/132714367

 

 

一、基础概念

1. 可重入锁

可重入锁表示的是,如果一个线程在未释放已获得锁的情况下再次对该对象加锁,将可以加锁成功。而且可以不断的加锁成功多次。但需要注意的是,每次加锁操作必须对应着一次释放锁的操作。 如以下示例是可以运行的(但完全没这么写的必要):

为什么需要可重入锁?先看以下示例(使用内置锁):

以上示例中,a方法调用b方法,两个方法都被内置锁锁定,如果不可重入,那么在调用b的时候当前线程就会等待锁的释放,而实际锁又被自己占用,因此死锁就出现了。而可重入锁就是为了解决这个问题而出现的。

那为什么a方法和b方法可能会需要同时加锁呢?这是因为外部对象可能会单独调用b方法而不去调用a方法!如果b没有进行加锁处理那么可能会导致并发问题。

注意:

实际上可重入锁如ReentrantLock在其内部有一个计数器用于保存当前线程对该锁的加锁次数;如果为0是表示当前线程没有获取到该锁。

2. 读写锁

读写锁内部实际上包含有两个锁对象:一个负责对读操作加锁,一个负责对写操作加锁。读操作不是排他的,也就是说同一时刻可以有多个线程同时占用读锁;而写操作必须是排它的,如果写锁被某个线程占有,那么任何的线程不但获取不到写锁,也获取不到读锁。 使用读写锁能够有效的提高并发;就是因为排它锁不允许同时读,而读写锁允许。

更详细的概念可参看:工藤新木:Java的各种概念锁

二、内置锁synchronized

对象的内置锁,它有以下特性:

  • 可以使用在方法或者代码段上; 但不可以使用在构造方法上。
  • 它是可重入的;
  • 当synchronized用于同一个对象时,同一时刻只有一个线程能够进入它被synchronized包围的区域。
  • 每一个对象都有一个内置锁,对象可以是类实例化后的对象,也可以是类本身。
  • 当内置锁使用在静态方法上时,表示的是对获取的类本身的内置锁,而不是实例化后的内置锁。

使用示例:

内置锁可以简化加锁操作,也能够避免在使用Lock的时候出现一些很常见的问题如死锁等。因此synchronized能够满足需求时可以考虑优先使用内置锁。

更多内置锁的知识可以参看:工藤新木:synchronized同步锁

但某些复杂场景下可能内置锁无法满足需求,如处理流程是下面这样的:

获取A锁后再获取B锁,然后先释放A锁。这种场景使用内置锁就无法满足。必须使用显示锁(Lock)。

三、显式锁Lock

显式锁可以提供比synchronized更加灵活的加锁功能。synchronized的所有使用场景显示锁都能够满足,而且还可以支持更多复杂的操作场景。

Java中的显式锁UML图如下所示:

它主要包含了两个接口和两个实现:

  • Lock: 最顶层的锁接口,提供加锁与释放锁的接口方法;
  • ReentrantLock:Lock的一个可重入锁的实现类;
  • ReadWriteLock: 读写锁接口,提供获取读锁对象与获取写锁对象两个接口方法;
  • ReentrantReadWriteLock:可重入读写锁的实现类。

显式锁主要的方法就是lock与unlock,先通过一个简单示例来演示锁的使用。

注意此处如果不加锁,在多线程环境下是有导致出问题的。多个线程同时向map中put同一个Key对应的值,最终存储的值将可能是某个线程put进去的,也可能都不是。

注意:

加锁后到释放锁前的所有操作都必须被try{}包围起来,并且必须在finally中释放锁。否则如果在释放锁前某个处理抛出异常,将不会进行锁的释放操作,这样的话其它线程就永远获取不到锁了。

锁常用操作

a. Lock接口

​b. ReadWriteLock接口

方法说明:

readLock返回一个读锁对象;writeLock返回一个写锁对象。

如下例,假设有Cache对象对数据按Key、Value进行缓存,写时互斥而读时可同时读,实现如下:

四、信号量Semaphore

信号量是一种轻量锁,它主要用于控制某些有限资源在多线程之间的分配使用。

假设最多只允许向数据库建立5个连接,那么同时有5个线程可以使用连接,如果同时请求的线程数超过5个,那么其它未获取许可的线程就只能等待正在运行中的线程释放连接。

Semaphore提供acquire()方法来获取许可,使用release()方法来释放许可,初始化的时候可以设置信号量的个数,也可以设置该信号量的公平性参数。

说明:

  • 公平性指的是对信号量的请求是否是FIFO(先入先出)的;如果设置成True,那么先调用acquire方法的线程将优先获取到信号量; 如果设置成False,那么将不会保证这个顺序,后提交的可能比在等待中的更加早的获取到信号量。默认情况下是设置成False的。
  • acquire方法也可以一次性获取多个信号量;当信号量数不够时,将会阻塞直到有信号量被其它线程释放并且数目足够。注意以下场景:如果设置成公平的,当前可使用的信号量为2个,A线程先申请的信号量为3个,B线程后申请2个,那么A与B都将会等待,而不会因为能够满足B线程的需求而优先让B线程获取到足够的信号量。

公平锁和非公平锁可以参看:工藤新木:Java的各种概念锁

下例模拟实现连接池。

信号量的使用方法可以分成两类,一类是acquire,一类是release,清单如下:

其中,每个acquire与release方法还有一个带int参数的变种,表示的是获取或者释放指定个数的信号量。

java中锁的详解 因此,重量级锁的开销较大,可能会导致线程阻塞和性能下降。但是,由于重量级锁提供了最高的线程安全性,所以在需要确保数据完整性和一致性的情况下,重量级锁是非常有用的。但是,由于轻量级锁不是互斥的,所以如果多个线程同时尝试获取锁,则可能导致数据不一致的问题。可重入锁(Reentrant Lock):可重入锁允许同一个线程多次获取同一个锁,这意味着线程可以在执行完同步代码后再次获取该锁而不需要重新竞争。自旋锁(Spin Lock):自旋锁是一种基于忙等待的同步机制,它在获取锁时会一直循环等待,直到获取到锁为止。 阅读详情

相关推荐

锁的艺术:Java并发中的常用锁策略与实践

对java锁相关内容进行整理分析:乐观锁 VS 悲观锁+自旋锁 VS 适应性自旋锁+无锁 VS 偏向锁 VS 轻量级锁 VS 重量级锁+公平锁 VS 非公平锁+可重入锁 VS 非可重入锁+独享锁 VS 共享锁

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 171万+

Java 锁的使用

悲观锁:总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁。 乐观锁:总是假设最好的情况,认为共享资源每次访问的时候不会出现问题,线程可以不停执行,无需加锁,只是在提交修改的时候去验证对应的资源是否被其他线程修改了。

KEEP CODING 968

Qupath软件的安装与使用

Qupath软件的安装与使用软件安装软件下载软件安装【windows版】简单使用文件打开人工标注标注导出和导入 Qupath是一款开源的医学图像标注软件,适合放射影像及数字病理切片等的查看。同时,其自带的标注功能使得医生可以直接通过该软件进行病变区域的标注和分类。跟进一步的,该软件提供groovy脚本运行接口,可供操作者编写和运行脚本,将标注信息转换为xml或者json格式的数据进行进一步的后序处...

qq_40662074的博客 3万+

java中的锁(基础篇)

java中基本锁 乐观锁 悲观锁 可重入锁 死锁 公平锁非公平锁 Synchronized关键字

jikeyeka的博客 1126

LIN总线CAPL函数实战——动态控制报文发送(linDeactivateSlot与linActivateSlot)

本文深入解析了LIN总线测试中动态控制报文发送的核心CAPL函数linDeactivateSlot与linActivateSlot的实战应用。通过详细拆解函数参数、生效范围及限制,并结合故障注入、功耗测试等实际场景的代码示例,指导测试工程师在仿真LIN主节点时,灵活调度报文发送,实现高效自动化测试。

weixin_29255731的博客 347

4、机器人建模、规划与控制及运动学知识解析

本博客深入解析了机器人建模、规划与控制的核心内容,涵盖运动学与动力学的基本原理,并结合典型应用场景探讨了移动机器人与操作器的控制策略。同时,博客还介绍了机器人技术的发展趋势及其在工业和服务领域的广泛应用。

desk3的博客 122

java开发中常见锁的使用场景和代码示例

线程同步和并发控制

weixin_45235440的博客 3811

IEC104协议学习专栏内容规划

IEC104协议的编程学习

sixtome 1109

java中常用的锁

概述:cas是一种无锁的原子操作机制,它可以在不加锁的情况下,保证多线程操作共享变量的原子性。它通过比较旧的变量的值是否和预期的值一致,如果一致则修改成功,如果不一致则进入重试状态。在java中cas广泛的应用与并发包中,想atomtic原子类,AQS等。虽然cas有较高的性能但是也存在一些问题,想ABA问题,自旋开销大,无法处理多个变量的原子性问题。优点:1、无锁,不会出现阻塞现象,提高并发的性能。2、避免使用 synchronized,减少上下文切换。缺点:1、出现ABA现象2、自旋开销大。

qq_41181702的博客 560

EtherCAT主站IGH-- 49 -- 搭建xenomai系统及自己的IGH主站

以上就是搭建xenomai系统及自己的IGH主站的内容。有不明白的地方欢迎留言;有建议欢迎留言,我后面编写文档好改进。创作不容,如果文档对您有帮助,记得给个赞。

常驻客栈的博客--嵌入式EtherCAT 3154

基于Simulink的固态变压器(SST)多级协同控制

本文基于Simulink平台,详细介绍了固态变压器(SST)多级协同控制的建模与仿真方法。针对SST三级架构(AC-DC、DC-DC、DC-AC)存在的级间耦合问题,提出了纵向解耦与横向联动的协同控制策略。通过搭建10kV/400V级联型SST系统模型,实现了输入电压波动±20%或负载0-100%跳变时直流母线电压波动小于2%的控制目标。文章详细讲解了Simulink建模步骤、控制算法推导及工程部署建议,包括功率前馈控制、虚拟惯性算法等关键技术。仿真结果表明,该协同控制方案能有效抑制负载突变时的电压波动,为

MHD0815的博客 214

Java常用锁

Java中常用锁 参考博客: https://www.tuicool.com/articles/NnQjyq http://www.cnblogs.com/mengdd/archive/2013/02/16/2913806.html 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 ...

Twilightuse93的专栏 513

数据分析案例-电影数据可视化分析

数据介绍数据为2011-2021电影数据可视化分析首先导入本次项目需要的包和数据 数据预处理 可视化

m0_64336780的博客 2万+

三、Java中七大常用锁实战

***/try {System.out.println("拿到锁");}).start();try {System.out.println("拿到锁");}).start();运行结果:结论:两个线程一直没有停止。通过JVM命令查看:在真实的业务中死锁一般不容易察觉!/***///从member移除这个优惠券return id;/***///构建对象。

zhenlong_qu的博客 1066

C#实现OPC客户端与S7-1200 PLC通信:工控场景稳定通信的实战指南(附完整代码)

标准化优先:OPC UA是工业通信的标准,相比直接通信,更适合多设备集成的工控场景;稳定性第一:必须封装断线重连、异常处理、资源释放逻辑,满足7×24小时运行需求;效率优化:高频采集场景优先用批量读写,避免单个变量频繁请求;细节把控:节点ID、变量类型、端口配置等细节是新手最容易踩坑的地方,建议先用UA Expert验证。这套代码和方案已在多个工业项目中落地,从单台S7-1200到多台S7-1200/1500集群,都能稳定运行。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1033

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

零基础学 Java 锁:从概念到代码,吃透 8 种常用锁

锁类型核心特性实现方式适用场景悲观锁阻塞竞争,冲突假设频繁写多、冲突频繁乐观锁无阻塞,冲突假设少,CAS 实现读多、冲突少(计数器、ID 生成)可重入锁同一线程可重复获取锁递归调用、多层锁嵌套公平锁按等待顺序分配,无饥饿对公平性要求高的场景非公平锁允许插队,效率高对效率要求高,可接受轻微不公平读写锁读 - 读共享,读 - 写 / 写 - 写互斥读多写少(缓存、统计)偏向锁单线程无竞争,开销最小synchronized 优化单线程重复加锁轻量级锁。

2201_75355172的博客 1559

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java 常用锁介绍

AQS (AbstractQueuedSynchronized) 是抽象队列同步器,它是构建锁的基础框架,常见的 ReentrantLock 锁、CountDownLatch 计数器都以AQS为基础框架,AQS 架构中有一个 Volatle 修饰的变量 state 用于记录锁的状态,如果有线程修改 state 值为 1,成功获取到所资源,其它线程尝试修改失败,会等待并存放到队列中等待锁的释放。AQS 与 Synchronized 比较。

sdfsfaffs的博客 771

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Java进阶(锁)——锁分类总结,Java中常用的锁的介绍

Java进阶(锁)——锁分类总结,Java中常用的锁的介绍

Arya的博客,专注后端领域 6279

java Lock常用锁

java Lock常用锁及示例

1167

Java中常用的锁分析总结

Java中常用的锁分析总结1.    ReentrantLock、ReentrantReadWriteLock及Sychronized简介(a)  类继承结构ReentrantLock类继承结构:ReentrantReadWriteLick类继承结构:简述:通过类的继承结构可以看出ReentrantLock 和 ReentrantReadWriteLock是拥有者两个不同类继承结构的体系,两者并无...

老花的博客 858

Java常用锁的实践

在 Java 中,锁是一种同步机制。用于防止多个线程同时访问同一资源。通过为临界区代码块(共享资源的访问代码)加锁,只有获得锁的线程才能执行这些代码,而其他线程需要等待,直到锁被释放。使用锁能够帮助我们解决多个线程同时访问共享资源时可能出现的各种问题,确保线程安全。非公平锁意味着在获取锁的请求上,不会遵循严格的 FIFO(先进先出)顺序。新请求的锁可以JUMP到队列前面,获取锁,而不必等到已有线程释放锁。竞争优先: 最新请求锁的线程可能获得锁,即使有其他线程在等待。可能会导致线程饥饿。

weixin_50055999的博客 1067

Java性能测试中常用的锁

锁及其应用。锁在多线程编程中扮演着重要的角色,确保共享资源的安全访问,同时也影响到应用程序的性能和可伸缩性。了解不同类型的锁以及它们的用途对于编写多线程程序至关重要。通过谨慎选择和正确使用锁,开发人员可以确保应用程序的正确性、性能和可伸缩性。在多线程编程中,锁是实现线程安全的关键工具,也是高效并发的基础。!!作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

2401_85696278的博客 755

Java中常用的分布式排他锁实现方式

在分布式系统中,实现排他锁需要跨节点的协调机制。根据具体场景选择合适方案,并结合框架(如Redisson、Curator)简化开发。:利用Consul的会话(Session)和KV存储实现锁。:利用etcd的事务和租约(Lease)机制实现锁。:利用数据库的唯一约束或乐观锁机制确保锁的互斥性。:高并发场景,如缓存更新、秒杀系统。:通过临时顺序节点和监听机制实现锁。:对一致性要求高的系统,如金融交易。:利用Redis的原子操作(如。:微服务环境中的服务协调。:低频操作或小型系统。)和Lua脚本实现锁。

ttyy1112的专栏 1198

Java中一些常用的锁整理

一、悲观锁和乐观锁 悲观锁:对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。在java中,synchronized关键字和Lock的实现类都是悲观锁 乐观锁:乐观锁认为自己在使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或

酷爱编程的小猿同学 1241
上一篇: java中共享变量的可见性:volatile与synchronized 
下一篇: 彻底理解 RESTful
ArtisticProgramming
博客等级 码龄8年 1粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值