ReentrantLock 始终由同一线程锁定和解锁
ReentrantLock lock and unlock by always the same thread
我正在尝试在多线程上实现可重入锁,但由于某种原因,同一个线程解锁然后再次锁定,导致 运行 始终是同一个线程,因此执行相同的操作。
下面是如何生成线程的代码
IntStream.range(0,(NUMBER_OF_THREADS)).forEach(index ->{
boolean operation = (index % 2 == 0) ? true : false;
Thread t = new Thread(new Client(operation,this));
t.start();
});
下面是线程的 运行 函数的工作原理
@Override
public void run() {
while(!Thread.interrupted()) {
System.out.println("Trying to acquire lock : " + main.getLock().tryLock()
+ " thread id " + Thread.currentThread().getName());
// if (main.getLock().tryLock()) {
try {
main.getLock().lock();
if(main.getLock().isHeldByCurrentThread()) {
System.out.println("Lock held by this thread " + main.getLock().isHeldByCurrentThread()
+ " thread id : " + Thread.currentThread().getName());
if (operation) {
main.getcAaccount().deposit(1);
} else {
main.getcAaccount().withdraw(2);
}
Thread.currentThread().sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("Thread id : " + Thread.currentThread().getName() + " unlocking");
main.getLock().unlock();//always have the unlock part here to ensure it unlock
}
}
它正确地打印出其他 5 个线程正在尝试获取锁并失败,然后线程 ID...正在解锁...并且同一线程立即再次锁定,即使它应该处于休眠状态。
在这个逻辑场景中我错过了什么吗?
提前谢谢你。
编辑建议修复的屏幕截图。
重入要求每次锁定后都要进行后续解锁。例如,如果我调用了 3 次 lock.lock()
,那么我应该也调用了 3 次 lock.unlock()
。在这一系列事件发生之前,ReentrantLock
不会认为自己已解锁。
您没有意识到 lock.tryLock()
,如果成功,本质上就像调用 lock.lock()
。因此,通过 lock
ing 两次,您还需要 unlock
两次。在您的代码示例中,您只解锁一次,因此最初锁定的线程在技术上仍然拥有锁。
修复它应该很简单,您可以从代码中删除第二个 lock.lock()
并且互斥应该仍然有效。要么,或者如果你需要阻塞锁定,则将 lock.tryLock()
替换为 lock.lock()
.
根据您的编辑, 您通过移除额外的锁解决了一个问题,但现在您 运行时间问题。你真的不需要 tryLock
。您可以将其替换为 lock
,因为 lock
调用将挂起线程并在锁已被持有时阻塞(最终在调用解锁时唤醒)。
我正在尝试在多线程上实现可重入锁,但由于某种原因,同一个线程解锁然后再次锁定,导致 运行 始终是同一个线程,因此执行相同的操作。
下面是如何生成线程的代码
IntStream.range(0,(NUMBER_OF_THREADS)).forEach(index ->{
boolean operation = (index % 2 == 0) ? true : false;
Thread t = new Thread(new Client(operation,this));
t.start();
});
下面是线程的 运行 函数的工作原理
@Override
public void run() {
while(!Thread.interrupted()) {
System.out.println("Trying to acquire lock : " + main.getLock().tryLock()
+ " thread id " + Thread.currentThread().getName());
// if (main.getLock().tryLock()) {
try {
main.getLock().lock();
if(main.getLock().isHeldByCurrentThread()) {
System.out.println("Lock held by this thread " + main.getLock().isHeldByCurrentThread()
+ " thread id : " + Thread.currentThread().getName());
if (operation) {
main.getcAaccount().deposit(1);
} else {
main.getcAaccount().withdraw(2);
}
Thread.currentThread().sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("Thread id : " + Thread.currentThread().getName() + " unlocking");
main.getLock().unlock();//always have the unlock part here to ensure it unlock
}
}
它正确地打印出其他 5 个线程正在尝试获取锁并失败,然后线程 ID...正在解锁...并且同一线程立即再次锁定,即使它应该处于休眠状态。
在这个逻辑场景中我错过了什么吗?
提前谢谢你。
编辑建议修复的屏幕截图。
重入要求每次锁定后都要进行后续解锁。例如,如果我调用了 3 次 lock.lock()
,那么我应该也调用了 3 次 lock.unlock()
。在这一系列事件发生之前,ReentrantLock
不会认为自己已解锁。
您没有意识到 lock.tryLock()
,如果成功,本质上就像调用 lock.lock()
。因此,通过 lock
ing 两次,您还需要 unlock
两次。在您的代码示例中,您只解锁一次,因此最初锁定的线程在技术上仍然拥有锁。
修复它应该很简单,您可以从代码中删除第二个 lock.lock()
并且互斥应该仍然有效。要么,或者如果你需要阻塞锁定,则将 lock.tryLock()
替换为 lock.lock()
.
根据您的编辑, 您通过移除额外的锁解决了一个问题,但现在您 运行时间问题。你真的不需要 tryLock
。您可以将其替换为 lock
,因为 lock
调用将挂起线程并在锁已被持有时阻塞(最终在调用解锁时唤醒)。