Java中有多少种锁?

Java中有多少种锁?

 

同学们,今天咱们聊聊Java里的“锁”。别害怕,咱们不是在研究门锁,而是Java并发编程中的各种锁机制。

 

说到锁,有的同学可能会头大:“锁这个东西太难了,每次学完过几天就忘了,还搞得代码跟一锅粥似的。”别急,老韩今天不但帮你梳理清楚Java中到底有多少种锁,还教你一套学习方法,让你学完就能运用,而且不容易遗忘!

 

来,抓紧你的板凳,带着脑袋里的那些“死锁”和“读写锁”,跟老韩开锁去了。

 

锁的作用是什么?

 

锁这个概念,最早来源于生活。想象一下,家里有个大门,如果没上锁,外面的人可以随便进来,那就乱套了。同理,在Java多线程中,如果多个线程同时访问同一段代码或数据,没有“锁”来约束,结果就是数据乱飞,Bug满天。

 

为什么需要锁?

 

• 保证数据安全:多个线程操作同一数据时,锁可以防止数据被“搞乱”。

• 实现同步控制:线程需要按照特定顺序执行时,锁可以帮忙“排队”。

 

Java中有多少种锁?

 

说到Java的锁,种类还真不少,但大致可以分为以下几类,咱们一一来说:

 

1. 偏向锁、轻量级锁和重量级锁

 

这三个锁是synchronized的核心机制,也是Java虚拟机层面的优化。

• 偏向锁:适合线程竞争少的场景,比如某个线程连续操作同一个锁对象时,锁直接“偏向”这个线程,无需加锁和解锁。

• 轻量级锁:多个线程访问同一个锁对象,但互相之间并没有频繁争抢时,轻量级锁上场。它通过CAS(Compare-And-Swap)操作来实现“乐观锁”,减少性能开销。

• 重量级锁:线程争抢激烈时,轻量级锁会升级为重量级锁,直接阻塞线程,等待唤醒。

 

老韩总结:锁的重量级别越低,性能越高,但适用场景更窄。

 

2. ReentrantLock(可重入锁)

 

ReentrantLock 是 java.util.concurrent.locks 包中的明星锁,它比 synchronized 更灵活。关键特性包括:

• 可重入:一个线程可以多次获取同一个锁,不会被自己阻塞。

• 可中断:支持 lockInterruptibly() 方法,在需要时中断线程。

• 公平锁和非公平锁:可以选择线程获取锁的顺序是否按“排队原则”。

 

适用场景:需要高度定制锁的行为,比如实现超时等待、检测死锁等。

 

3. 读写锁(ReadWriteLock)

 

读写锁是个效率神器!它允许多个线程同时读,只要没有线程在写数据。

• 读锁:共享锁,多个线程可以同时获取,互不干扰。

• 写锁:独占锁,只有一个线程可以获得,其他线程必须等待。

 

适用场景:读多写少的场景,比如配置文件读取、日志分析。

 

4. StampedLock

 

StampedLock 是读写锁的“加强版”,提供了一种基于“时间戳”的锁机制。

• 乐观读锁:线程读数据时不需要阻塞其他线程,只有在检测到数据变化时才升级为悲观锁。

• 悲观读锁/写锁:和传统的读写锁类似。

 

适用场景:需要极致性能优化,且对并发安全有更高要求。

 

5. CountDownLatch 和 CyclicBarrier

 

虽然这俩不是“锁”的字面意思,但在并发控制中,确实可以起到类似锁的作用。

• CountDownLatch:倒计时锁。比如你想等所有线程完成任务再做某件事,就可以用它。

• CyclicBarrier:循环屏障。它允许一组线程相互等待,达到一定数量后继续执行。

 

适用场景:任务分解与合并,比如并行计算、大型数据处理。

 

6. Semaphore(信号量)

 

Semaphore 可以控制同时访问某资源的线程数量。简单理解,它就像一个停车场,最多允许固定数量的车进入,多了就得排队。

 

适用场景:限制资源使用,比如限制数据库连接池的最大连接数。

 

7. 自旋锁和自定义锁

 

• 自旋锁:线程在等待锁时不会进入阻塞状态,而是“自旋”一段时间,直到获取锁或超时退出。它适合锁的持有时间非常短的场景。

• 自定义锁:基于 AbstractQueuedSynchronizer(AQS)实现,可以设计适合特定需求的锁机制。

 

怎么学锁才能学了就会用,还不容易忘?

 

锁这个东西,说难不难,说简单也不简单,关键在于方法。老韩给你支几招,包你学了就能用,还不容易忘。

 

1. 用真实场景理解锁的作用

 

别把锁当成死记硬背的理论,而是结合日常生活去理解。

• 偏向锁像“你专属的钥匙”,别人用不到。

• 轻量级锁像“老式公寓的门锁”,简单、便捷,但不够安全。

• 重量级锁像“银行金库的门”,非常稳固,但进出麻烦。

 

2. 先从简单锁开始,逐步升级

 

不要一上来就搞复杂的 ReentrantLock、StampedLock,先把 synchronized 理解透彻,学会什么时候锁住代码块、什么时候锁住方法。

 

3. 动手写代码,边用边学

 

锁这种东西,不写代码根本记不住。比如:

• 用 ReentrantLock 写个简单的银行账户取款场景,理解“公平锁”和“可重入锁”。

• 用 ReadWriteLock 写个商品库存管理系统,看看读写锁如何提高性能。

 

4. 读源码,强化理解

 

锁的底层实现很大程度依赖于 CAS 和 AQS。建议多看看 ReentrantLock 的源码,它的实现逻辑非常清晰,看明白了其他锁的原理也就懂了。

 

写在最后:锁的核心是解决问题,不是复杂化问题

 

同学们,锁的本质,是为了解决多线程中的同步问题,但它从来不是用来“炫技”的工具。不要觉得用复杂锁就显得自己很牛,关键在于用对场景、用好工具。

 

记住:锁不是越多越好,简单有效的方案才是王道。

 

好了,今天就聊到这儿,老韩要去帮学生优化一个读写锁的案例,下次咱们继续深挖Java中的并发神器!

npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: sass-loader@12.1.0 npm ERR! Found: webpack@3.12.0 npm ERR! node_modules/webpack npm ERR! peer webpack@"^1.9 || ^2 || ^2.1.0-beta || ^2.2.0-rc || ^3.0.0" from uglifyjs-webpack-plugin@0.4.6 npm ERR! node_modules/webpack/node_modules/uglifyjs-webpack-plugin npm ERR! uglifyjs-webpack-plugin@"^0.4.6" from webpack@3.12.0 npm ERR! peer webpack@"2 || 3 || 4" from babel-loader@7.1.5 npm ERR! node_modules/babel-loader npm ERR! dev babel-loader@"^7.1.1" from the root project npm ERR! 9 more (extract-text-webpack-plugin, file-loader, ...) npm ERR! npm ERR! Could not resolve dependency: npm ERR! peer webpack@"^5.0.0" from sass-loader@12.1.0 npm ERR! node_modules/sass-loader npm ERR! dev sass-loader@"^12.1.0" from the root project npm ERR! npm ERR! Conflicting peer dependency: webpack@5.88.2 npm ERR! node_modules/webpack npm ERR! peer webpack@"^5.0.0" from sass-loader@12.1.0 npm ERR! node_modules/sass-loader npm ERR! dev sass-loader@"^12.1.0" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution. npm ERR! npm ERR! npm ERR! For a full report see: npm ERR! C:\Users\antiy\AppData\Local\npm-cache\_logs\2023-07-18T05_47_37_165Z-eresolve-report.txt npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\antiy\AppData\Local\npm-cache\_logs\2023-07-18T05_47_37_165Z-debug-0.log
07-20
回答: 当使用yarn安装依赖时,如果出现"has unmet peer dependency"的警告,意味着某个依赖的peer dependency没有被满足。peer dependency是指一个包对于另一个包的依赖关系,但是它们并不是直接的依赖关系。在这种情况下,yarn不会自动安装peer dependency,而是需要手动安装。\[1\]所以,当你遇到这个警告时,你需要手动安装所需的peer dependency。在你的例子中,警告是"rollup-plugin-typescript"需要"tslib@*"和"typescript@>=2.1.0"这两个peer dependency。你可以使用命令"yarn add tslib typescript"来手动安装这两个依赖。\[2\]另外,根据\[3\]的心得,当使用npm安装包出现错误或者速度过慢时,可以考虑使用yarn或者cnpm进行尝试。 #### 引用[.reference_title] - *1* *2* [包管理器 - peer dependency 的安装](https://blog.csdn.net/anleng6817/article/details/101126789)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [解决sass-loader@13.2.0has unmet peer dependencywebpack@^5.0.0](https://blog.csdn.net/qq_61402485/article/details/129628084)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值