在多线程环境下,当你的转账操作被重复提交💸、库存被超卖📉、计数器结果离奇错误❌时,背后往往是因为缺乏合理的锁控制。而悲观锁作为Java并发中最「简单粗暴」的解决方案,从JDK1.0时代的重量级锁⛓️,到如今JVM层级的锁升级优化⚡,其底层实现堪称一部高性能并发的发展史📜。
本文将带你穿透**synchronized
关键字**的表面语法,直击三大核心问题💡:
synchronized
如何实现性能飞跃?**(偏向锁/轻量级锁的取舍智慧)📌 举个真实案例:某电商平台在秒杀活动中使用synchronized
导致TPS从8000📈暴跌到300📉,最终通过缩小锁粒度+锁分离优化提升15倍性能🚀——我们将在文中用代码还原这个优化过程。
下面我们直接切入正题,从操作系统与JVM的协作契约🤝开始讲起!
锁记录(Lock Record)是jvm用来支持轻量级锁的数据结构,是线程私有的,用于记录锁的状态,锁拥有者的信息以及竞争情况等等.
在竞争情况下,多个线程会通过锁记录进行协调,实现了对轻量级锁的竞争和重量化的升级。当多个线程竞争同一把锁时,会通过锁记录中的信息协调竞争关系,避免无谓的自旋和竞争。
偏向锁:当没有没有锁竞争时可以用偏向锁来优化
偏向锁的加锁过程:
synchronized(obj)
代码块时,会先检查该对象的锁标记是否为偏向锁,是偏向锁且线程ID与当前线程ID一致,则无需加锁,直接进入代码块偏向锁撤销过程:
轻量级锁:如果有多个线程使用synchronized对一个对象加锁,但是加锁的时间是错开的,不会发生竞争时,可以使用轻量级锁来优化.
static final Object obj = new Object();
public static void method1(){
synchronized(obj){
method2()
}
}
public static void method2(){
synchronized(obj){
}
}
轻量级锁的加锁过程:
轻量级锁的解锁过程:
轻量级锁竞争:当前线程加轻量级锁的CAS操作失败时,说明发生了锁的竞争,这时当前线程会进行自旋获取锁.自旋是通过忙等待,在一个循环中不断获取锁
自旋锁膨胀为重量级锁:当自旋达到一定的阈值时,会导致锁膨胀,将轻量级锁膨胀为重量级锁
在Java多线程中,ReentrantLock是一个可重入锁,相比与synchronized有更多的灵活性
共同点:
可重入
:ReentrantLock和synchronized都是可重入锁,即对一个对象反复加锁不同点:
锁等待可终止
:ReentrantLock允许一个线程在等待锁的过程中被其他线程打断,然后可以选择继续等待获取终止.synchronized获取锁的过程中是不可被打断的超时时间
:ReentrantLock允许设置获取锁的超时时间,超过时间之后可以放弃获取这个锁.synchronized不能设置超时时间公平锁选择
:ReentrantLock允许选择公平锁或者非公平锁.synchronized只有非公平锁多个条件变量
:ReentrantLock提供了Condition允许多个条件变量存在,也就是多个waitlist,可以让线程满足某个条件时等待,也可以让其他线程满足某个条件时唤醒.synchronized只有一个条件变量private Lock lock = new ReentrantLock()
lock.lock()
:获取锁,不可被打打断lock.unlock()
:释放锁lock.lockInterruptibly()
:可打断,获取锁:获取锁失败进入阻塞状态时,可以被其他线程的interrput方法打断lock.trylock()
:尝试获得锁,返回值是boolean,true获取锁成功,false获取锁失败lock.trylock(long n,TimeUnit.SECONDS)
:尝试获得锁,获取不到锁等待n单位时间,时间到了还没获取到锁就返回false,时间内获取到锁还是返回true,支持可打断new ReentrantLock(true)
:设置公平锁,默认为falseCondition condition = lock.newCondition()//Condition可以创建多个也就是支持多个条变量
condition.await()
:await使用前需要获取锁,调用后释放锁,进入condition条件变量中等待,被唤醒(打断)后继续竞争lock锁,竞争成功后继续执行condition.await(long timeout,TimeUnit unit)
:等待指定超时时间condition.signal()
:从condition中随机唤醒一个等待中的线程condition.signalAll()
:从condition中唤醒全部等待中的线程condition.awaitUninterruptibly()
:等待不可被打断try {
// 获取锁 : 不可被打断
lock.lock();
// 在这里执行需要同步的代码块
} finally {
// 释放锁
reentrantLock.unlock();
}
特性 | synchronized | ReentrantLock |
---|---|---|
条件变量 | 单个 | 多个 |
可中断 | ❌ | ✅ |
超时控制 | ❌ | ✅ |
公平锁 | ❌ | ✅ |
System.out.println(ClassLayout.parseInstance(obj).toPrintable())
monitor -c 5 com.example.MyClass methodName
"悲观锁用性能换取安全,而真正的艺术在于找到那个平衡点⚖️"
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有