以编程方式确定哪个 Java 线程持有锁
-
09-06-2019 - |
题
是否可以在运行时以编程方式检查持有给定对象锁的线程的名称?
解决方案
你只能判断当前线程是否持有普通锁(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 来做各种有趣的事情,包括查找持有的锁。您无法获得实际的对象,但您确实可以获得类和身份哈希值(这不是唯一的)。
跑步 控制台. 。它包含在 Java SDK 中并从命令行运行。我不确定你使用的是什么操作系统,但在 Windows 上你可以将 java 进程的 PID 传递给它。它应该可以帮助您找到导致问题的线程。或者,您可以使用商业分析器(例如 YourKit)或任意数量的其他分析器。
在 1.5 中,您可以找到所有线程并获取每个线程的状态,例如:
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 线程状态
您可以通过调用来检查特定对象上的锁定 wait()
或者 notify()
该对象上的方法。如果对象没有持有锁,那么它将抛出 llegalMonitorStateException
.
2- 通过致电 holdsLock(Object o)
方法。这将返回布尔值。
如果是 可重入锁 你可以检查它是否被当前线程持有
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;
}
}
丑陋但有效。
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);
}
}