如何理解Java中眼花缭乱的各种并发锁?

本文详细讲解了Java并发编程中的各种锁,包括互斥锁、读写锁、重入锁、公平锁、悲观锁、自旋锁、偏向锁等。介绍了它们的由来、应用场景和优缺点,并通过实例解释了锁升级的过程。最后,文章提供了一份锁应用的脑图和面试题,帮助读者深入理解并掌握Java并发锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在互联网公司面试中,很多小伙伴都被问到过关于锁的问题。 今天,我给大家一次性把Java并发锁的全家桶彻底讲明白。包括互斥锁、读写锁、重入锁、公平锁、悲观锁、自旋锁、偏向锁等等等等。视频有点长,大家一定要全部看完,保证你会醍醐灌顶。

1、锁的由来

在并发编程中,经常会遇到两个以上的线程访问同一个共享变量,当同时对共享变量进行读写操作时,就会产生数据不一致的情况。

在这里插入图片描述

随着线程并发技术的发展,在多线程环境中,对线程访问资源的限制也越来越多。为了保证资源获取的有序性和占用性,都是通过并发锁来控制的。

2、锁的应用场景

下面,我根据个人经验以及并发场景下线程的处理逻辑,总结为以下7个场景,不同场景使用不同的锁。

1)某个线程是否锁住同步资源的情况

如果要锁住同步资源则使用悲观锁,不锁住同步资源使用乐观锁。 所谓悲观锁,就是每次拿数据的时候都认为会有别人修改,所以在读数据的时候都会上锁,其他线程数据就会阻塞,直到拿到锁。

在这里插入图片描述

举个例子,假设厕所只有一个坑位,悲观锁就是上厕所会第一时间把门反锁上,这样其他人上厕所只能在门外等候,这就是阻塞。

在这里插入图片描述

而乐观锁就是开着门,当然在这个场景下一般也不会这么做。所以,乐观锁,就是每次拿数据的时候都假设为别人不会修改,所以不会上锁;只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新了,要么报错,要么自动重试。

在这里插入图片描述

乐观锁与悲观锁是一种广义上的概念,没有谁优谁劣。乐观锁适用于写少读多的场景,因为不用上锁、释放锁,省去了锁的开销,从而提升了吞吐量。 而悲观锁适用于写多读少的场景,因为线程间竞争激励,如果使用乐观锁会导致线程不断进行重试,这样反而还降低了性能。

2)多个线程是否共享一把锁的情况

如果在并发情况下,多个线程共享一把锁就是使用共享锁,如果不能共享一把锁就是排它锁或者叫独占锁、独享锁。 共享锁是指锁可被多个线程所持有。如果一个线程对数据加上共享锁后,那么其他线程只能对数据再加共享锁,不能加独占锁。获得共享锁的线程只能读数据,不能修改数据。

### Java 中复杂字符串处理 在Java编程环境中,除了基本的字符串连接外,还存在多种方式可以实现更复杂的字符串处理。这些功能不仅限于简单的拼接操作,还包括模式匹配、替换以及解析等高级特性。 #### 正则表达式的应用 正则表达式提供了强大的文本搜索能力,在Java中可以通过`java.util.regex.Pattern`类和`Matcher`对象来进行复杂的字符串查找与替换工作[^1]。例如: ```java import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexExample { public static void main(String[] args) { Pattern pattern = Pattern.compile("\\bcat\\b"); Matcher matcher = pattern.matcher("A cat and a kitten."); while (matcher.find()) { System.out.println("Found the text \"" + matcher.group() + "\" starting at index " + matcher.start() + " and ending at index " + matcher.end()); } } } ``` 这段代码展示了如何利用正则表达式去定位特定单词边界内的目标词(如"cat"),并打印其出现的位置信息。 #### 字符串拆分与组合 当面对由固定分隔符分割的数据集时,可采用`split()`方法将其分解成数组;反之,则可通过`join()`函数重新组装回原始形式或者构建新的复合结构。 ```java // Splitting strings into arrays based on delimiters. String sentence = "apple,banana,cherry"; String[] fruits = sentence.split(","); for (String fruit : fruits) { System.out.println(fruit); } // Joining elements of an array back together with specified separators. List<String> listFruits = Arrays.asList("orange", "grape", "melon"); String joinedSentence = String.join("-", listFruits); System.out.println(joinedSentence); // Output: orange-grape-melon ``` 上述例子说明了怎样高效地管理以逗号作为间隔符的一系列项目名称,并能够灵活调整它们之间呈现的方式。 #### 编码转换及国际化支持 考虑到不同国家和地区使用的字符编码差异较大,因此Java内置有专门针对多字节字符的支持机制——即Unicode标准下的各种变体。这使得程序能够在保持数据一致性的前提下跨越不同的语言环境运行良好[^2]。 此外,对于某些特殊情况下可能出现的乱码现象,开发者应当熟悉掌握诸如ISO-8859-1至UTF-8等多种常见编码格式间的相互转化技巧,从而确保应用程序在全球范围内都能稳定可靠地执行预期任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tom 弹架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值