不同的锁分类
- 互斥锁:确保同一时刻只有一个线程可以执行锁定的代码。
- 读/写锁:允许多个线程同时读取,但写入时需要独占访问。
- 乐观锁:允许一个线程假设没有其他线程修改数据,进行读操作,而不持有完整的锁。
- 公平锁与非公平锁:决定获取锁的顺序是随机的还是按照请求的顺序。
- 可重入锁:同一个线程可以多次获取已经持有的锁。
synchronized锁的优化
synchronized锁自JDK 1.0以来已经经过多次优化,尤其是在JDK 1.6中引入了锁的升级优化机制,包括偏向锁、轻量级锁和重量级锁的概念,这些优化旨在减少锁操作的开销和提高多线程性能。- 演进过程:
偏向锁 -> 轻量级锁(自旋锁)-> 重量级锁
偏向锁(Biased Locking):
- 偏向锁是一种锁优化,它假设锁将被同一个线程多次获取。
- 实现原理:
- 偏向锁会在对象头的Mark Word中存储获取它的线程ID,进入同步块时只需要检查这个线程ID是否为当前线程的ID,如果是,就没有竞争。
轻量级锁(Lightweight Locking):
- 如果偏向锁失败,JVM将锁升级为轻量级锁。
- 实现原理:
- 在栈中创建锁记录(Lock Record)和在对象头中复制Mark Word来实现。
- 当线程试图获取锁时,它使用CAS(Compare-And-Swap)操作尝试将锁对象的标记指向锁记录。(自旋尝试)
- 如果成功,该线程持有锁;
- 如果失败,表示有其他线程竞争,锁升级为重量级锁。
重量级锁(Heavyweight Locking):
- 当有多个线程同时竞争同一个锁时,轻量级锁会升级为重量级锁。
- 实现原理:
- 通过操作系统内的互斥量来实现,涉及到线程从用户态切换到核心态,增加了额外的开销。
- 重量级锁能够让其他线程进入阻塞状态,直到锁被释放。
Lock
除了传统的
synchronized关键字,JUC还提供了Lock,以提供更灵活、更复杂的锁操作,以适应不同的使用场景。不同Lock的关系
- 注:由mermaid描述,网页若无法显示,可复制后到mermaid网站在线预览
横向对比
特征/锁类型 | ReentrantLock | ReentrantReadWriteLock | StampedLock |
作用 | 提供灵活的锁管理和多条件变量支持。 | 分离读写操作,允许多读单写。 | 提供能力基的锁管理,性能优于ReadWriteLock。 |
使用场景 | 需要灵活的锁管理,多条件变量,或公平锁。 | 适用于读多写少的数据结构,如缓存。 | 读操作远超写操作的内存数据结构。 |
特性 | 可重入;支持公平和非公平锁;提供尝试锁、定时尝试锁和可中断的锁。 | 读锁共享,写锁排他;支持公平和非公平策略。 | 提供写锁、悲观读锁和乐观读;不是可重入的。 |
注意事项 | 确保锁得到释放;公平锁可能影响性能;注意死锁风险。 | 锁获取和释放必须匹配;不支持锁降级。 | 不支持条件变量;必须验证戳的有效性;确保锁的释放。 |
不同Lock的使用
ReentrantLock
- 使用
ReentrantLock来同步一些修改共享资源的操作。
ReentrantReadWriteLock
- 使用
ReentrantReadWriteLock来分别控制读取和写入操作,适用于读多写少的情况。
StampedLock
- 使用
StampedLock进行乐观读取,同时支持写入。乐观读取可以提高并发性,因为不阻塞写入操作。
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/01HVXFGKYHRYDQR50MT9CR65Z9
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!