我有一个 Java 程序,它具有一个管理多个相同守护线程的主类。主类有一个守护线程访问的静态
ReentrantLock
。主类创建线程,启动它们,并根据用户输入中断它们。其他线程(都是同一类的实例)被编码为在首先释放锁(如果它们拥有锁)后中断时终止。没有其他代码与锁交互(即使在主类中也没有)。按照我对守护进程类进行编码的方式,守护进程线程在不首先获取锁的情况下不可能执行任何操作。如果 Thread.holdsLock()
没有返回错误的值,则在不首先释放锁的情况下不可能重新获得锁(即保持计数始终为 1 或 0)。我正在运行 Eclipse JavaFX Maven 项目。
这是类的 run() 方法的伪代码示例:
// setup
while(!exitCondition)
try {
myLock.lockInterruptibly();
// do stuff
if(exitCondition) tellMain(); // this causes main to interrupt all threads
// sleep for a bit
} catch (InterruptedException e) {
// clean up
break;
} finally {
if(Thread.holdsLock(myLock)) myLock.unlock();
}
}
// termination message
如果我删除 if 语句,则每个不拥有锁的线程都会抛出
IllegalMonitorStateException
。我已经盯着这个问题好几个小时了,没有看到如果调用它的线程拥有锁,Thread.holdsLock() 有任何方法返回 false。管理线程的方法不会以任何方式与锁交互。这是怎么回事?
java中有2个不相关的锁定系统。你将其中一种与另一种混合在一起,这是行不通的。有
java.util.concurrent.Lock
以及所有相关业务,但与它完全无关,“团队同步”,其中包括以下功能:
Thread.holdsLock
<-- there's your problemobj.wait()
+ obj.notify
/ obj.notifyAll
synchronized
,关键字。你正在混合和匹配,这是行不通的。如果你想知道一个线程是否持有juc锁,你不能这样做。它不是 juc lock 的 API 的一部分。
synchronized
更类似于操作系统正在做的事情,juc lock 更抽象一些。特别是考虑到光纤(Loom 项目,JDK21 中的新项目),您可能需要 juc 锁。但是,如果您需要 holdsLock
,您可以自己编写(您可以包装一个锁并注册哪个线程持有它),或者使用低级(“团队同步”)锁。
holdsLock
表示“假”,因为该线程不持有 synchronized
锁。让 Thread.holdsLock(foo)
返回 true 的唯一方法是使用 synchronized (foo) { / * now Thread.holdsLock(foo); will be true */ }
。
如果您想解锁 Juc 锁,只需这样做,然后抓住如果您从未持有过它就会出现的
IllegalStateException
。
如果您的锁特别是
j.u.c.ReentrantLock
,而且很可能是,那么,您do有一个可以使用的方法。将 Thread.holdsLock(myLock)
替换为 myLock.isHeldByCurrentThread()
。请注意,您的 myLock
param/field/var 需要输入 ReentrantLock
。 RL有这个方法; j.u.c.Lock 没有(该接口尝试应用于尽可能多的实现,也许并非所有实现都希望/能够跟踪哪个线程实际持有它)。
当且仅当当前线程持有指定对象的监视器锁时返回 true。
监视器锁或内在锁是指
synchronized
关键字(monitorenter
和monitorexit
指令)使用的lovk。
在您的示例中,您使用的
ReentrentLock
与内在锁不同,因此 Thread#holdsLock
不适用。