在Java并发编程中,ReentrantLock是常用的显式锁实现,相比synchronized关键字,它提供了更灵活的锁操作能力,其中tryLock方法就是实现非阻塞锁获取的核心方法。非阻塞锁可以让线程在获取锁失败时不会进入等待队列,而是直接返回结果,适合对响应速度要求较高的场景。

tryLock方法的基本介绍
ReentrantLock的tryLock方法有两个重载版本,分别用于不同的非阻塞锁获取需求:
- 无参tryLock():尝试获取锁,如果锁当前没有被其他线程持有,则立即获取锁并返回true;如果锁已经被持有,则立即返回false,不会阻塞当前线程。
- 有参tryLock(long timeout, TimeUnit unit):尝试在指定的等待时间内获取锁,如果在等待时间内锁变为可用且当前线程没有被中断,则获取锁并返回true;如果等待时间结束仍未获取到锁,或者线程在等待过程中被中断,则返回false。
无参tryLock的使用示例
无参tryLock适合不需要等待的场景,线程获取锁失败后立即执行其他逻辑,以下是简单的代码示例:
import java.util.concurrent.locks.ReentrantLock;
public class TryLockDemo {
// 创建ReentrantLock实例
private static final ReentrantLock lock = new ReentrantLock();
private static int count = 0;
public static void main(String[] args) {
// 创建两个线程模拟竞争锁
Thread thread1 = new Thread(() -> {
// 尝试获取锁
if (lock.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + " 获取到锁,开始处理业务");
// 模拟业务处理
count++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放锁,必须在finally中执行避免死锁
lock.unlock();
System.out.println(Thread.currentThread().getName() + " 释放锁");
}
} else {
System.out.println(Thread.currentThread().getName() + " 获取锁失败,执行其他逻辑");
}
}, "线程1");
Thread thread2 = new Thread(() -> {
if (lock.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + " 获取到锁,开始处理业务");
count++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " 释放锁");
}
} else {
System.out.println(Thread.currentThread().getName() + " 获取锁失败,执行其他逻辑");
}
}, "线程2");
thread1.start();
thread2.start();
}
}
上述代码中,两个线程同时启动尝试获取锁,只有一个线程能成功获取锁,另一个线程会直接执行获取锁失败的逻辑,不会阻塞等待。
有参tryLock的使用示例
有参tryLock适合需要短暂等待锁的场景,线程会在指定时间内尝试获取锁,以下是代码示例:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class TryLockWithTimeoutDemo {
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
try {
// 尝试在2秒内获取锁
if (lock.tryLock(2, TimeUnit.SECONDS)) {
try {
System.out.println(Thread.currentThread().getName() + " 在2秒内获取到锁");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} else {
System.out.println(Thread.currentThread().getName() + " 2秒内未获取到锁,放弃等待");
}
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 等待锁的过程中被中断");
}
}, "线程1");
Thread thread2 = new Thread(() -> {
try {
// 尝试在3秒内获取锁
if (lock.tryLock(3, TimeUnit.SECONDS)) {
try {
System.out.println(Thread.currentThread().getName() + " 在3秒内获取到锁");
} finally {
lock.unlock();
}
} else {
System.out.println(Thread.currentThread().getName() + " 3秒内未获取到锁,放弃等待");
}
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 等待锁的过程中被中断");
}
}, "线程2");
thread1.start();
// 让线程1先启动获取锁
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
上述代码中,线程1获取锁后会持有3秒,线程2尝试在3秒内获取锁,由于线程1持有锁的时间超过线程2的等待时间,线程2会返回获取锁失败的结果。
使用tryLock实现非阻塞锁的注意事项
- 锁的释放必须放在finally代码块中,避免获取锁后业务代码抛出异常导致锁无法释放,引发死锁问题。
- 有参tryLock方法会抛出InterruptedException,需要正确处理线程中断的情况,避免中断逻辑被忽略。
- tryLock获取锁成功后,当前线程持有锁的状态和正常lock方法获取的一致,支持重入操作,重入时不需要再次调用tryLock。
- 非阻塞锁适合锁持有时间较短的场景,如果锁竞争非常激烈且持有时间较长,非阻塞逻辑可能会导致大量线程频繁尝试获取锁,反而增加CPU开销。
tryLock与lock方法的对比
可以通过以下表格清晰对比两种方法的区别:
| 对比项 | lock方法 | tryLock方法 |
|---|---|---|
| 阻塞性 | 阻塞,直到获取锁 | 非阻塞,立即返回或等待指定时间后返回 |
| 返回值 | 无返回值 | 返回boolean,表示是否获取锁成功 |
| 中断响应 | 不响应中断,直到获取锁 | 有参版本响应中断,无参版本不响应中断 |
| 适用场景 | 锁竞争不激烈,可接受等待的场景 | 锁竞争激烈,需要快速响应或避免阻塞的场景 |
通过合理使用ReentrantLock的tryLock方法,开发者可以灵活实现非阻塞锁逻辑,根据业务场景选择合适的重载版本,提升并发程序的执行效率和响应速度。
ReentrantLocktryLock非阻塞锁Java并发修改时间:2026-06-23 22:00:18