本文目录导读:

我来为你详细讲解轻量级锁(Lightweight Lock)的案例。
轻量级锁概述
轻量级锁是Java SE 1.6中引入的锁优化机制,用于在没有多线程竞争或竞争不激烈的情况下,减少传统重量级锁(synchronized)使用操作系统互斥量产生的性能消耗。
轻量级锁的工作流程:
graph TD
A[线程执行同步代码块] --> B{检查Mark Word}
B -->|无锁状态| C[复制Mark Word到锁记录]
B -->|已持有锁| D[重入计数]
C --> E[CAS尝试将Mark Word替换为指向锁记录的指针]
E -->|成功| F[获取轻量级锁成功]
E -->|失败| G{Escape分析检查}
F --> H[执行代码块]
G -->|无竞争| I[膨胀为重量级锁]
G -->|有竞争| J[进入阻塞状态]
H --> K[执行完毕释放锁]
K --> L[CAS恢复Mark Word]
L -->|成功| M[锁释放完成]
L -->|失败| N[唤醒等待线程]
具体代码案例
案例1:基础轻量级锁使用
public class LightweightLockExample {
private int count = 0;
// 使用synchronized关键字(默认优先使用轻量级锁)
public synchronized void increment() {
count++;
}
public static void main(String[] args) throws InterruptedException {
LightweightLockExample example = new LightweightLockExample();
// 单线程访问时,会使用轻量级锁
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
example.increment();
}
long endTime = System.currentTimeMillis();
System.out.println("单线程执行时间: " + (endTime - startTime) + "ms");
System.out.println("最终count值: " + example.count);
}
}
案例2:无竞争场景演示
public class NoContentionExample {
private int value = 0;
public void updateValue(int newValue) {
synchronized (this) { // 轻量级锁场景
value = newValue;
// 模拟短暂操作
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
NoContentionExample example = new NoContentionExample();
// 单线程连续操作,没有竞争,适合轻量级锁
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
example.updateValue(i);
}
long endTime = System.currentTimeMillis();
System.out.println("无竞争场景执行时间: " + (endTime - startTime) + "ms");
}
}
案例3:锁重入场景
public class LockReentrancyExample {
private StringBuilder sb = new StringBuilder();
// 模拟锁重入
public synchronized void append(String text) {
sb.append(text);
appendMore(); // 再次获取同一把锁(重入)
}
private synchronized void appendMore() {
sb.append("!");
}
public static void main(String[] args) {
LockReentrancyExample example = new LockReentrancyExample();
// 单线程调用,轻量级锁支持重入
example.append("Hello");
System.out.println("重入结果: " + example.sb.toString());
// 批量操作
example.sb.setLength(0);
long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
example.append("test");
example.sb.setLength(0);
}
long end = System.currentTimeMillis();
System.out.println("重入操作耗时: " + (end - start) + "ms");
}
}
案例4:膨胀为重量级锁的场景
public class LockInflationExample {
private int sharedData = 0;
private static final int THREAD_COUNT = 5;
// 多线程竞争时,会从轻量级锁膨胀为重量级锁
public void modifySharedData() {
synchronized (this) { // 竞争激烈时膨胀
sharedData++;
try {
Thread.sleep(50); // 增加持锁时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) throws InterruptedException {
LockInflationExample example = new LockInflationExample();
// 创建多个线程竞争锁
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 10; j++) {
example.modifySharedData();
}
});
threads[i].start();
}
// 等待所有线程完成
for (Thread thread : threads) {
thread.join();
}
// 查看锁膨胀后的性能影响
System.out.println("多线程竞争完成,最终值: " + example.sharedData);
}
}
案例5:偏向锁到轻量级锁的升级
public class BiasToLightweightExample {
private static class LockObject {
int data = 0;
}
public static void main(String[] args) throws InterruptedException {
LockObject lock = new LockObject();
// 阶段1:单一线程获取锁(可能使用偏向锁)
long start1 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
synchronized (lock) {
lock.data++;
}
}
long end1 = System.currentTimeMillis();
System.out.println("单线程阶段耗时: " + (end1 - start1) + "ms");
// 阶段2:另一个线程开始访问(可能升级为轻量级锁)
Thread otherThread = new Thread(() -> {
long start2 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
synchronized (lock) {
lock.data++;
}
}
long end2 = System.currentTimeMillis();
System.out.println("第二线程阶段耗时: " + (end2 - start2) + "ms");
});
otherThread.start();
otherThread.join();
System.out.println("最终data值: " + lock.data);
}
}
性能对比测试
public class LockPerformanceTest {
private int count = 0;
// 使用synchronized(轻量级锁)
public synchronized void syncIncrement() {
count++;
}
// 使用Lock(需要处理)
public void lockIncrement() {
count++;
}
public static void main(String[] args) throws InterruptedException {
LockPerformanceTest test = new LockPerformanceTest();
// 单线程测试
long start1 = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
test.syncIncrement();
}
long end1 = System.nanoTime();
System.out.println("单线程synchronized耗时: "
+ (end1 - start1) / 1_000_000 + "ms");
// 多线程测试
int threadCount = 4;
Thread[] threads = new Thread[threadCount];
long start2 = System.nanoTime();
for (int i = 0; i < threadCount; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 250000; j++) {
test.syncIncrement();
}
});
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
long end2 = System.nanoTime();
System.out.println("多线程synchronized耗时: "
+ (end2 - start2) / 1_000_000 + "ms");
}
}
核心要点总结
| 特性 | 说明 |
|---|---|
| 适用场景 | 多线程交替执行,竞争不激烈 |
| 实现方式 | CAS操作 + Mark Word复制 |
| 优点 | 避免操作系统互斥量开销,响应快速 |
| 缺点 | 竞争激烈时膨胀为重量级锁 |
| 升级条件 | CAS失败且存在竞争 |
| JVM参数 | -XX:+UseSpinning 等 |
最佳实践建议
public class BestPracticeExample {
private volatile int version = 0;
// 使用局部变量减少锁竞争
public void bestPractice() {
int localCount = 0;
synchronized (this) {
localCount = version;
// 短时间操作
localCount++;
version = localCount;
}
}
// 使用Lock替代synchronized(显式控制)
private final java.util.concurrent.locks.ReentrantLock lock =
new java.util.concurrent.locks.ReentrantLock();
public void explicitLock() {
lock.lock();
try {
// 业务逻辑
} finally {
lock.unlock();
}
}
}
监控和调试
可以通过JVM参数查看锁状态:
# 打印锁信息 -XX:+PrintLockInflation # 偏向锁设置 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
轻量级锁是JVM对synchronized的重要优化,理解其工作原理有助于编写高性能的并发代码,在竞争不激烈时性能非常好,竞争激烈时JVM会自动升级策略。