Synchronized是Java中实现线程同步的核心关键字,JDK 15版本之后官方默认禁用了偏向锁优化,这一改动对并发性能的影响需要结合具体场景分析。偏向锁的设计初衷是在无锁竞争或竞争极少的场景下,减少获取锁的CAS操作开销,禁用后锁的升级路径会直接从无锁状态进入轻量级锁阶段。
偏向锁的工作机制与禁用背景
偏向锁的核心逻辑是当线程第一次获取锁时,会在对象头中记录线程ID,后续该线程再次获取锁时不需要执行CAS操作,直接判断线程ID匹配即可进入同步块。JDK官方禁用偏向锁的主要原因是偏向锁的撤销需要等待全局安全点,在高并发场景下撤销操作的开销反而超过了其带来的收益,同时偏向锁的实现复杂度较高,维护成本大。
分析影响的核心维度
分析禁用偏向锁的影响需要从以下三个维度展开:
- 场景锁竞争程度:无竞争、低竞争、高竞争场景下的性能变化差异极大
- 锁持有时间:短持有时间和长持有时间场景下,锁升级的开销占比不同
- 业务线程模型:单线程重复获取锁、多线程交替获取锁、多线程同时竞争锁的场景表现不同
具体的分析方法与步骤
1. 确认当前JDK的偏向锁配置
首先通过JVM参数确认偏向锁是否开启,执行以下命令查看默认配置:
java -XX:+PrintFlagsFinal -version | grep BiasedLocking
如果输出中BiasedLockingStartupDelay为0且UseBiasedLocking为true,说明偏向锁开启;JDK 15及以上默认UseBiasedLocking为false。
2. 设计基准测试对比
使用JMH框架编写不同竞争场景的测试用例,分别测试开启和关闭偏向锁时的吞吐量、平均响应时间。以下是一个低竞争场景的测试示例:
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
@Fork(1)
@Warmup(iterations = 3)
@Measurement(iterations = 5)
public class BiasedLockBenchmark {
private int count = 0;
private final Object lock = new Object();
@Benchmark
public void synchronizedIncrement() {
synchronized (lock) {
count++;
}
}
public static void main(String[] args) throws Exception {
org.openjdk.jmh.runner.Runner runner = new org.openjdk.jmh.runner.Runner(new org.openjdk.jmh.runner.options.OptionsBuilder()
.include(BiasedLockBenchmark.class.getSimpleName())
.build());
runner.run();
}
}
分别用以下JVM参数运行测试:
- 开启偏向锁:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
- 关闭偏向锁:-XX:-UseBiasedLocking
对比两次测试的吞吐量结果,低竞争场景下开启偏向锁的吞吐量通常会更高,禁用后吞吐量会有一定程度下降。
3. 实际业务场景压测
在测试环境部署实际业务应用,分别开启和关闭偏向锁进行压测,监控以下指标:
- 接口平均响应时间、99分位响应时间
- 线程阻塞次数、锁等待时间
- CPU使用率,重点关注用户态CPU和内核态CPU的占比
可以通过以下JVM参数输出锁相关的统计信息:
-XX:+PrintConcurrentLocks -XX:+PrintGCApplicationStoppedTime
4. 高竞争场景的额外验证
如果业务中存在高并发竞争同一把锁的场景,禁用偏向锁反而可能带来性能提升,因为避免了偏向锁撤销的开销。可以模拟高竞争场景测试:
import java.util.concurrent.CountDownLatch;
public class HighContentionTest {
private static int count = 0;
private static final Object lock = new Object();
private static final int THREAD_NUM = 100;
private static final int LOOP_NUM = 100000;
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(THREAD_NUM);
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_NUM; i++) {
new Thread(() -> {
for (int j = 0; j < LOOP_NUM; j++) {
synchronized (lock) {
count++;
}
}
latch.countDown();
}).start();
}
latch.await();
long end = System.currentTimeMillis();
System.out.println("总耗时:" + (end - start) + "ms");
System.out.println("最终count值:" + count);
}
}
运行该代码时分别开启和关闭偏向锁,观察总耗时的变化,高竞争场景下禁用偏向锁的耗时通常会更短。
影响判断与优化建议
根据测试结果可以得出以下结论:
- 如果业务中大部分同步块处于无竞争或低竞争状态,禁用偏向锁会导致性能下降,可考虑评估是否开启偏向锁,或优化同步块粒度减少锁竞争
- 如果业务中存在较多高竞争场景,禁用偏向锁反而能提升性能,不需要额外调整
- 如果锁持有时间极短,偏向锁的收益有限,禁用后的影响可以忽略
对于需要开启偏向锁的场景,可以在JVM启动参数中添加-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0恢复偏向锁功能,但需要注意JDK 15之后偏向锁已被标记为废弃,未来版本可能会完全移除,长期优化方向还是减少不必要的锁竞争,或改用其他并发工具如ReentrantLock、StampedLock等。
Synchronized偏向锁JDK_15并发性能性能分析修改时间:2026-06-26 13:12:26