1. 概述
Project Lombok 是一个 Java 库,通过提供各种注解来生成标准方法和功能,从而减少样板代码。例如,我们可以用 Lombok 自动生成 getter/setter、构造函数,甚至引入建造者模式等设计模式。
本教程将学习 Lombok 1.18.32 版本引入的 @Locked 注解的使用方法。
2. 为什么需要 @Locked 注解?
首先理解 @Locked 注解的必要性:
Java 21 引入了虚拟线程来简化并发应用的实现、维护和调试。与传统线程不同,虚拟线程由 JVM 而非操作系统管理,因此:
- ✅ 无需系统调用即可分配
- ✅ 不依赖操作系统上下文切换
但需警惕虚拟线程的潜在性能问题:
- ❌ 当阻塞操作发生在
synchronized
块或方法内时,仍会阻塞操作系统线程 - 这种情况称为 线程钉死(Pinning)
- ✅ 若阻塞操作在
synchronized
块外,则不会引发问题
线程钉死会显著影响应用性能,尤其当:
- 阻塞操作频繁调用
- 阻塞操作耗时较长
⚠️ 短暂且不频繁的阻塞操作通常不会造成问题
解决方案:用 ReentrantLock
替代 synchronized
—— 这正是 Lombok 新注解的用武之地。
3. 理解 @Locked 注解
简单来说:
- @Locked 是
ReentrantLock
的变体实现 - 专为虚拟线程优化设计
核心特性:
- ✅ 仅可用于静态或实例方法
- 自动将方法体包装为获取锁的代码块
- 可指定
ReentrantLock
类型的字段作为锁对象 - 方法执行结束后自动释放锁
4. 依赖配置
在 pom.xml
中添加 lombok 依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
⚠️ 需使用 1.18.32 或更高版本
5. 使用方法
创建 Counter
类,包含 increment()
和 get()
方法:
public class Counter {
private int counter = 0;
private ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public int get() {
lock.lock();
try {
return counter;
} finally {
lock.unlock();
}
}
}
counter++
不是原子操作,需加锁保证多线程环境下的可见性
用 @Locked 简化代码:
@Locked
public void increment() {
counter++;
}
@Locked
public int get() {
return counter;
}
工作原理
- Lombok 自动创建
ReentrantLock
字段(实例方法用$lock
,静态方法用$LOCK
) - 将方法体包装为获取锁的代码块
- 方法退出时自动释放锁
⚠️ 多个 @Locked 方法默认共享同一把锁。如需独立锁,需显式声明
ReentrantLock
字段并指定名称
测试用例:
@Test
void givenCounter_whenIncrementCalledMultipleTimes_thenReturnCorrectResult() throws InterruptedException {
Counter counter = new Counter();
Thread.Builder builder = Thread.ofVirtual().name("worker-", 0);
Runnable task = counter::increment;
Thread t1 = builder.start(task);
t1.join();
Thread t2 = builder.start(task);
t2.join();
assertEquals(2, counter.get());
}
5.1. @Locked.Read 和 @Locked.Write 注解
替代 ReentrantReadWriteLock
的专用注解:
- @Locked.Read:获取读锁
- @Locked.Write:获取写锁
改造 Counter
类:
@Locked.Write
public void increment() {
counter++;
}
@Locked.Read
public int get() {
return counter;
}
✅ 读写分离锁可显著提升性能,尤其在高负载读写场景
⚠️ 同一类中混用 @Locked.Read/@Locked.Write 时,需显式指定锁字段名避免冲突
6. @Locked 与 @Synchronized 的区别
Lombok 还提供类似功能的 @Synchronized 注解,主要差异:
特性 | @Locked | @Synchronized |
---|---|---|
替代对象 | ReentrantLock |
synchronized 关键字 |
锁对象 | Lombok 生成的专用字段 | 默认锁定 this 或类对象 |
虚拟线程兼容性 | ✅ 完全兼容 | ❌ 可能导致线程钉死 |
适用场景 | 虚拟线程环境 | 传统线程环境 |
⚠️ 虚拟线程环境下强烈推荐使用 @Locked
7. 总结
本文系统介绍了 Lombok 的 @Locked 注解:
- ✅ 为虚拟线程优化而生
- ✅ 简化
ReentrantLock
的使用 - ✅ 支持读写分离锁(@Locked.Read/@Locked.Write)
- ✅ 比 @Synchronized 更适合虚拟线程场景
完整源码见 GitHub 仓库。