Java并发:ReentrantLock的tryLock方法执行不符合预期求排查
ReentrantLock tryLock() 表现不符合预期的问题排查
问题场景
测试ReentrantLock的tryLock()方法时,创建两个线程,预期一个线程获取锁执行if块逻辑,另一个线程因锁不可用进入else块,但实际两个线程都成功获取锁并执行了安全操作。
问题根源
你的代码中,ReentrantLock是ReentrantLockMethods类的成员变量,每个线程实例(t1、t2)初始化时都会创建独立的ReentrantLock对象。这意味着两个线程的锁完全没有关联,不存在竞争关系,自然都能通过tryLock()获取到自己的锁。
修复方案
要让线程之间产生锁竞争,必须让所有线程共享同一把ReentrantLock实例,有两种常见实现方式:
方式1:将锁声明为static静态变量
修改ReentrantLockMethods类,把锁定义为static,让所有线程实例共享这一把锁:
import java.util.concurrent.locks.ReentrantLock; class ReentrantLockMethods extends Thread{ // 静态变量,所有线程共享同一锁实例 private static ReentrantLock l = new ReentrantLock(); public ReentrantLockMethods(String name) { super(name); } public void run() { if(l.tryLock()) { System.out.println(Thread.currentThread().getName()+"....got Lock and performing safe operations"); try { Thread.sleep(5000); } catch(InterruptedException e) { e.printStackTrace(); } l.unlock(); } else { System.out.println(Thread.currentThread().getName()+ "....unable to get Lock hence, performing alternate operations"); } } }
方式2:通过构造方法传入共享锁
在主线程中创建一个ReentrantLock实例,然后通过构造方法传递给每个线程对象:
import java.util.concurrent.locks.ReentrantLock; class ReentrantLockMethods extends Thread{ private ReentrantLock l; // 构造方法接收外部传入的锁 public ReentrantLockMethods(String name, ReentrantLock lock) { super(name); this.l = lock; } public void run() { if(l.tryLock()) { System.out.println(Thread.currentThread().getName()+"....got Lock and performing safe operations"); try { Thread.sleep(5000); } catch(InterruptedException e) { e.printStackTrace(); } l.unlock(); } else { System.out.println(Thread.currentThread().getName()+ "....unable to get Lock hence, performing alternate operations"); } } } public class ReentrantLockDemo1 { public static void main(String[] args) { // 创建共享锁实例 ReentrantLock sharedLock = new ReentrantLock(); ReentrantLockMethods t1 = new ReentrantLockMethods("First Thread", sharedLock); ReentrantLockMethods t2 = new ReentrantLockMethods("Second Thread", sharedLock); t1.start(); t2.start(); } }
验证结果
修改后运行程序,会符合预期:要么其中一个线程获取锁执行安全操作,另一个进入else块执行备选逻辑,顺序取决于线程调度。
内容的提问来源于stack exchange,提问作者vitaminC
相关产品推荐
相关产品推荐

