Java各种锁

本文详细介绍了Java中锁的四种状态:无锁、偏向锁、轻量级锁和重量级锁,以及锁的状态升级机制。探讨了轻量级锁如何在无多线程竞争下减少重量级锁的性能消耗,并介绍了自旋锁和自适应自旋锁的优化手段。最后,讲解了锁消除和锁粗化的概念,以及它们如何提高程序性能。

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

锁主要存在四种状态,无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。只可升级不可降级,为了提高获得锁和释放锁的效率。

偏向锁

会偏向于第一个获得它的线程,在接下来的执行中,该锁没有被其他线程获取,那么持有偏向锁的线程就不需要同步。
因为多线程情况下申请锁的线程很可能都不同,所以在锁竞争比较激烈的场合就会失效了。失效后并不会立即膨胀为重量级锁,而是先升级为轻量级锁。

轻量级锁(JDK1.6之后引入)

不是为了代替重量级锁,本意是在没有多线程竞争下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗,因为使用轻量级锁时不需要申请互斥量,另外轻量级锁的加锁和解锁都用到了CAS操作。
一般情况下对于大部分锁,在整个同步周期内都是不存在竞争的。 如果没有竞争,轻量级锁通过使用CAS操作避免了使用互斥操作的开销。 但是如果存在锁竞争,除了互斥量开销外,还会额外发生CAS操作,这样会比重量级锁更慢。锁竞争会膨胀为重量级锁。

自旋锁和自适应自旋

轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,会进行名为自旋锁
的优化手段。
互斥同步对性能影响最大的影响就是阻塞的实现,因为挂起、恢复线程的操作都需要转入内核态中完成(用户态-内核态会耗费时间)。
一般线程持有锁的时间都不是太长,为了这一点时间而去挂起/恢复线程是得不偿失的,为了让一个线程等待,我们只需要让一个线程执行一个忙循环(自旋)即可
百度百科-自旋锁

何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。

在JDK1.6之后引入了自适应的自旋锁。对于之前的改进就是:自旋的时间不再固定,而是和前一次同一个锁上的自旋时间以及锁的拥有者来决定。

锁消除

在虚拟机即使编译器在运行时,如果检测到那些共享数据不可能存在竞争,那么就执行锁消除。锁消除可以节省毫无意义的请求锁的时间。

锁粗化

平常在写代码的时候,都要求将同步块的区域限制的很小,只在共享数据的实际作用域才进行同步。但是如果一系列的连续操作都对同一对象反复加锁和解锁,会有不必要的性能消耗。

参考资料:https://github.com/Snailclimb/JavaGuide/blob/master/Java相关/synchronized.md

### Java 中各种机制的区别与用法 #### 1. **`synchronized`** `synchronized` 是 Java 提供的一种内置机制,用于控制多线程环境下的资源访问。它的特点是简单易用,但在灵活性上有所欠缺。 - **特点**: - 自动管理的获取和释放[^4]。 - 不支持尝试获取、可中断的获取等功能。 - **适用场景**: - 当不需要高级功能(如超时获取或条件变量)时,适合使用 `synchronized`[^3]。 ```java public class SynchronizedExample { public synchronized void methodA() { System.out.println("Method A"); } public void methodB() { synchronized (this) { System.out.println("Method B"); } } } ``` --- #### 2. **`ReentrantLock`** `ReentrantLock` 是 `java.util.concurrent.locks.Lock` 接口的一个实现类,提供了比 `synchronized` 更强大的功能。 - **特点**: - 支持公平和非公平[^1]。 - 可以通过 `tryLock()` 方法尝试获取。 - 支持可中断的获取 (`lockInterruptibly`) 和带超时的获取 (`tryLock(long time, TimeUnit unit)`)[^4]。 - 允许绑定多个 `Condition` 对象,从而实现复杂的线程同步逻辑。 - **注意事项**: - 必须显式地调用 `unlock()` 来释放。 - 性能开销可能高于 `synchronized`。 ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private final ReentrantLock lock = new ReentrantLock(); public void methodC() { lock.lock(); try { System.out.println("Method C with ReentrantLock"); } finally { lock.unlock(); } } } ``` --- #### 3. **`ReadWriteLock`** `ReadWriteLock` 是一种读写分离的机制,允许多个线程同时读取共享数据,但只允许单一线程修改数据。 - **特点**: - 提高了并发性能,尤其是在读操作远多于写操作的情况下[^5]。 - 包含两个子:`readLock` 和 `writeLock`[^2]。 - **适用场景**: - 数据结构主要以读为主,偶尔有写的场景下表现优异。 ```java import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockExample { private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); private int value; public void readValue() { rwLock.readLock().lock(); try { System.out.println("Read Value: " + value); } finally { rwLock.readLock().unlock(); } } public void writeValue(int newValue) { rwLock.writeLock().lock(); try { value = newValue; System.out.println("Wrote New Value: " + value); } finally { rwLock.writeLock().unlock(); } } } ``` --- #### 4. **总结对比** | 特性/类型 | `synchronized` | `ReentrantLock` | `ReadWriteLock` | |--------------------|-----------------------------------|------------------------------------------|---------------------------------------| | 是否需要手动解 | 否 | 是 | 是 | | 尝试获取 | 不支持 | 支持 | 支持 | | 超时获取 | 不支持 | 支持 | 支持 | | 多条件对象支持 | 不支持 | 支持 | 支持 | | 并发性能 | 较低 | 较高 | 高(适用于读多写少场景) | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值