在运行时,是否可以以编程方式检查持有给定对象锁的线程名称?
在运行时,是否可以以编程方式检查持有给定对象锁的线程名称?
您只能通过使用Thread.holdsLock(Object)
方法判断当前线程是否持有普通锁。您不能在没有本地代码的情况下获取拥有锁的线程引用。
然而,如果您需要进行复杂的线程操作,建议您熟悉java.util.concurrent包。 ReentrantLock
允许您获取其所有者(但它是受保护的方法,因此您需要扩展它)。根据您的应用程序,可能会发现使用并发包后,您根本不需要再获取锁的所有者。
还有一些非编程方法可以找到锁的所有者,例如向JVM发送信号以将线程转储到stderr,有助于确定死锁的原因。
使用反射可以获取由线程持有的锁。这仅适用于Java 1.6。
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] ti = bean.getThreadInfo(bean.getAllThreadIds(), true, true);
在每个ThreadInfo对象上都有LockInfo对象,您可以使用它们的identityHashCode来与所讨论的锁进行比较。
从1.6版本开始,您可以使用JMX来执行各种有趣的操作,包括查找被持有的锁。您无法获取实际对象,但可以获得类和身份哈希值(该值不是唯一的)。
(此帖子最初链接到我现在已废弃的Web日志中的示例。)
运行jconsole。它包含在Java SDK中,并从命令行运行。我不确定您使用的是哪个操作系统,但在Windows上,您只需将其传递给Java进程的PID即可。它应该帮助您找到导致问题的线程。或者,您可以使用商业分析器(如YourKit或任何其他分析器)。
Map<Thread,StackTraceElement[]> map = Thread.getAllStackTraces();
for (Map.Entry<Thread, StackTraceElement[]> threadEntry : map.entrySet()) {
log.info("Thread:"+threadEntry.getKey().getName()+":"+threadEntry.getKey().getState());
for (StackTraceElement element : threadEntry.getValue()) {
log.info("--> "+element);
}
}
Thread.getState可以提供有关线程是否处于BLOCKED,WAITING等状态的信息,请参见jdk api ThreadState
如果是可重入锁,您可以检查它是否被当前线程持有。
final ReentrantLock lock = new ReentrantLock();
lock.isHeldByCurrentThread();
当您获取锁时,可以使用变量来保存当前线程,然后在其他人尝试使用它时打印它。
Thread holderOfLock = null;
Object theLock = new Object();
public void doStuff()
{
if(holderOfLock != null)
{
//get and print name of holderOfLock-thread or get stacktrace etc.
}
synchronized (theLock)
{
holderOfLock = Thread.currentThread();
//do stuff...
holderOfLock = null;
}
}
wait()
或notify()
方法来检查该对象上的锁。如果对象没有持有锁,则会抛出IllegalMonitorStateException
异常。holdsLock(Object o)
方法。这将返回布尔值。丑陋但有效。
String findLockOwner(ReentrantLock lock) {
String patternStr = "\\[Locked by thread (\\S+)\\]";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(lock.toString());
boolean matchFound = matcher.find();
if (matchFound && matcher.groupCount() >= 1) {
return matcher.group(1);
}
}