Java同步锁Lock的基本概念
在Java多线程编程中,当多个线程同时访问共享资源时,可能会引发数据不一致的问题,为了解决这一问题,Java提供了多种同步机制,其中java.util.concurrent.locks.Lock接口是一种灵活且强大的同步工具,与synchronized关键字相比,Lock提供了更广泛的锁定操作,例如可中断的获取锁、超时获取锁以及公平性选择等,使得线程同步控制更加精细。

Lock接口的核心方法
Lock接口定义了几个核心方法,是实现线程同步的基础:
lock():获取锁,如果锁被其他线程持有,当前线程会阻塞直到锁被释放。unlock():释放锁,通常在finally块中调用,确保锁一定会被释放,避免死锁。tryLock():尝试获取锁,如果锁可用则立即返回true,否则返回false,不会阻塞线程。tryLock(long time, TimeUnit unit):在指定时间内尝试获取锁,超时后返回false,支持中断响应。lockInterruptibly():可中断地获取锁,如果在获取锁过程中被中断,会抛出InterruptedException。
ReentrantLock的使用示例
ReentrantLock是Lock接口最常用的实现类,它支持可重入(同一线程可多次获取锁)和公平性(按请求顺序分配锁)选择,以下是一个基本使用示例:

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock(); // 获取锁
try {
count++; // 临界区操作
} finally {
lock.unlock(); // 释放锁
}
}
public static void main(String[] args) {
LockExample example = new LockExample();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + example.count); // 输出2000
}
}
与synchronized的对比
Lock与synchronized的主要区别在于:
- 灵活性:Lock支持非阻塞获取锁(
tryLock())和可中断获取锁(lockInterruptibly()),而synchronized是阻塞式的。 - 公平性:ReentrantLock可设置为公平锁(
new ReentrantLock(true)),按线程请求顺序分配锁,而synchronized是非公平的。 - 锁绑定:Lock需手动释放锁(
unlock()),容易因异常导致死锁,而synchronized在异常时会自动释放锁。 - 功能扩展:Lock可与Condition结合实现精确的线程间通信,而
synchronized只能配合wait()/notify()使用。
Condition的使用
Lock接口允许创建多个Condition对象,用于实现线程的分组唤醒,以下示例展示了生产者-消费者模型:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionExample {
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean isProduced = false;
public void produce() throws InterruptedException {
lock.lock();
try {
while (isProduced) {
condition.await(); // 等待消费
}
System.out.println("Produced");
isProduced = true;
condition.signal(); // 唤醒消费者
} finally {
lock.unlock();
}
}
public void consume() throws InterruptedException {
lock.lock();
try {
while (!isProduced) {
condition.await(); // 等待生产
}
System.out.println("Consumed");
isProduced = false;
condition.signal(); // 唤醒生产者
} finally {
lock.unlock();
}
}
}
注意事项
- 锁的释放:确保在
finally块中调用unlock(),避免锁泄漏。 - 死锁风险:避免嵌套获取多个锁,或按固定顺序获取锁以防止死锁。
- 性能考量:在低竞争场景下,
synchronized性能更优;在高竞争或需要高级功能时,Lock更合适。
通过合理使用Lock接口,开发者可以更灵活地控制线程同步,确保多线程环境下的数据安全性和程序稳定性。
















