🔍 开发者资源导航 🔍 |
---|
🏷️ 博客主页: 个人主页 |
📚 专栏订阅: JavaEE全栈专栏 |
锁策略
如果你自己需要实现一把锁(你认为标准库给你的锁不够用)你需要关注锁策略,其实大多数情况synchronized已经足够用了,但是java面试中常常会考QwQ。
所谓锁策略,就是在加锁的时候有什么特点,有什么行为。
常见的锁策略有六种:
- 悲观锁/乐观锁
- 重量级锁/轻量锁
- 挂起等待锁/自旋锁
- 互斥锁/读写锁
- 可重入锁/不可重入锁
- 公平锁/非公平锁
1. 悲观锁/乐观锁
如果我们预测,线程尝试获取一个锁的时候,获取频率很低,这种情况一般称其为乐观情况,反之称其为悲观。
乐观锁:加锁的时候,预测接下来的竞争不激烈
,获取频率较高
,不需要
做额外工作,例如让两个线程去竞争一个锁。
悲观锁:加锁的时候,预测接下来的竞争非常激烈
,获取频率较低
,需要
针对这样的情况做额外工作,例如100个线程去竞争一个锁。
乐观锁在遇到竞争时,可以即使获取到锁,悲观锁在遇到竞争时获取的概率较低。
2.重量级锁/轻量锁
重量级锁和轻量级锁是对于悲观和乐观场景的解决方案。
重量级锁:在悲观场景下要付出更多
的代价,更低效
轻量锁:在乐观场景下要付出更少
的代价,更高效
3.挂起等待锁/自旋锁
挂起等待锁/自旋锁是重量级锁/轻量锁的典型具体实现方法。
自旋锁:获取锁的周期更短
,在等待时会采取忙等的方法,能够及时获取到锁,这个过程一直消耗cpu。
重量级锁:获取锁的周期更长
,在遇到竞争时,会进入阻塞状态等待内核唤醒,因此很难做到及时获取,但是这个过程不必一直消耗cpu,把cpu省下来干别的事情。
4.互斥锁/读写锁
互斥锁:在一个线程已经获取到锁的情况下,其他的任何线程尝试获取时都会产生互斥。
读写锁:
读写锁对于读多写少的情况进行了优化。
在这种情况下读和读会产生线程安全吗?显然是不会的,只有在涉及到读写的情况才会产生线程安全。
因此我们在读读时不需要进行互斥,而涉及到读写时会产生互斥。
而这就是读写锁的特点:
-
读读共享:多个读线程可以同时获取读锁
-
读写互斥:读锁和写锁不能同时持有
-
写写互斥:同一时间只能有一个线程持有写锁
-
可重入性:线程可以重复获取已经持有的锁
5.可重入锁/不可重入锁
可重入锁:线程可以重复获取已经持有的锁。
不可重入锁:线程不可以重复获取已经持有的锁。
典型的就是常用的synchronized,它就是一个可重入锁,在此种情况下就不会陷入死锁状态。
synchronized(locker) {
//...
synchronized(locker) {
//...
}
}
6.公平锁/非公平锁
公平锁:遵循时间的先来后到。
非公平锁:遵循每一个线程概率相等。
在默认情况下他是非公平的状态,实现公平锁需要付出一些代价,比如说使用一个队列去记录各个线程获取锁的顺序。
感谢各位的观看Thanks♪(・ω・)ノ,如果觉得满意的话留个关注再走吧。