【多线程】计算机领域中的各种锁
【多线程】计算机领域中的各种锁
本文来自于我关于多线程系列文章。欢迎阅读、点评与交流
1.【多线程】互斥锁(Mutex)是什么?
2.【多线程】计算机领域中的各种锁
3.【多线程】信号量(Semaphore)是什么?
4.【多线程】信号量(Semaphore)常见的应用场景
计算机领域的锁种类繁多,它们可以从不同的维度进行分类,例如实现层面、设计思想、状态策略等。下面这个表格梳理了常见的锁类型、核心特征以及典型的应用场景或代表实现。
锁的类型 | 核心特征 | 应用场景 / 代表实现 |
---|---|---|
🔒 按实现层面 | ||
互斥锁 (Mutex) | 独占访问,未获取锁的线程会被阻塞 | 操作系统同步机制,Java synchronized 的底层 |
读写锁 (ReadWriteLock) | 共享读(多个线程可同时读),独占写(写时互斥) | ReentrantReadWriteLock (Java),适用于读多写少的场景 |
自旋锁 (Spinlock) | 尝试获取锁失败时,进行忙等待(循环),避免线程切换 | 适用于锁持有时间极短的场景;Java 中的 CAS 操作 |
条件变量 (Condition Variable) | 与互斥锁配合,用于等待某个条件成立,会释放互斥锁 | 线程间协同,如生产者-消费者模型 |
信号量 (Semaphore) | 计数器,控制同时访问资源的线程数量 | 限制并发线程数,连接池资源管理 |
🔒 按设计思想 | ||
乐观锁 (Optimistic Locking) | 假设冲突很少,先直接修改,提交时用版本号或CAS检测冲突 | 数据库版本号、Java AtomicInteger 等原子类 |
悲观锁 (Pessimistic Locking) | 假设冲突频繁,访问资源前先加锁,确保独占 | Java synchronized 关键字、ReentrantLock |
🔒 按状态策略(特指 synchronized) | ||
偏向锁 (Biased Locking) | 仅一个线程访问时,通过标记避免同步操作 | Java synchronized 的锁优化初始状态 |
轻量级锁 (Lightweight Locking) | 少量线程竞争时,通过 CAS 自旋尝试获取锁 | synchronized 竞争加剧时的状态 |
重量级锁 (Heavyweight Locking) | 竞争激烈时,未获锁线程会被操作系统挂起阻塞 | synchronized 竞争进一步加剧的状态 |
🔒 按其他特性 | ||
可重入锁 (Reentrant Lock) | 同一线程可多次获取同一把锁,防止死锁 | Java ReentrantLock 、synchronized |
公平锁 / 非公平锁 (Fair/Non-fair) | 公平锁按申请顺序分配;非公平锁允许插队,吞吐量通常更高 | ReentrantLock(true) 为公平锁,默认非公平 |
分段锁 (Segmented Lock) | 细化锁粒度,将数据分段,每段独立加锁 | ConcurrentHashMap (JDK7) 中的 Segment |
💡 理解锁的升级与优化
Java中的synchronized
关键字是理解锁优化的一个好例子。为了平衡性能和安全性,JVM会根据竞争情况自动进行锁升级:无锁 → 偏向锁 → 轻量级锁 → 重量级锁。这个过程旨在减少不必要的重量级锁开销。此外,JVM还会进行锁粗化,将多个连续的加锁、解锁操作合并为一个范围更大的锁,以减少性能损耗。
💎 小结与建议
选择哪种锁取决于你的具体场景:
- 追求极致性能且冲突概率小:考虑乐观锁。
- 写操作频繁或临界区逻辑复杂:悲观锁更稳妥。
- 读远多于写:读写锁可以显著提升并发度。
- 锁持有时间非常短:自旋锁能避免线程切换的开销。
- 需要复杂的线程协作:条件变量是标准工具。