以编程方式确定哪个Java线程持有锁

46

在运行时,是否可以以编程方式检查持有给定对象锁的线程名称?


1
请修改您的标题和帖子,以表明您指的是Java。标签不应该是放置与问题相关的关键信息的唯一位置。 - Adam Davis
9个回答

31

您只能通过使用Thread.holdsLock(Object)方法判断当前线程是否持有普通锁。您不能在没有本地代码的情况下获取拥有锁的线程引用。

然而,如果您需要进行复杂的线程操作,建议您熟悉java.util.concurrent包。 ReentrantLock允许您获取其所有者(但它是受保护的方法,因此您需要扩展它)。根据您的应用程序,可能会发现使用并发包后,您根本不需要再获取锁的所有者。

还有一些非编程方法可以找到锁的所有者,例如向JVM发送信号以将线程转储到stderr,有助于确定死锁的原因。


21

使用反射可以获取由线程持有的锁。这仅适用于Java 1.6。

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] ti = bean.getThreadInfo(bean.getAllThreadIds(), true, true);

在每个ThreadInfo对象上都有LockInfo对象,您可以使用它们的identityHashCode来与所讨论的锁进行比较。


7

从1.6版本开始,您可以使用JMX来执行各种有趣的操作,包括查找被持有的锁。您无法获取实际对象,但可以获得类和身份哈希值(该值不是唯一的)。

(此帖子最初链接到我现在已废弃的Web日志中的示例。)


4

运行jconsole。它包含在Java SDK中,并从命令行运行。我不确定您使用的是哪个操作系统,但在Windows上,您只需将其传递给Java进程的PID即可。它应该帮助您找到导致问题的线程。或者,您可以使用商业分析器(如YourKit或任何其他分析器)。


3
在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 ThreadState


2

如果是可重入锁,您可以检查它是否被当前线程持有。

final ReentrantLock lock = new ReentrantLock();
lock.isHeldByCurrentThread();

1

当您获取锁时,可以使用变量来保存当前线程,然后在其他人尝试使用它时打印它。

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;
    }
}

1
你可以通过在特定对象上调用wait()notify()方法来检查该对象上的锁。如果对象没有持有锁,则会抛出IllegalMonitorStateException异常。
2- 通过调用holdsLock(Object o)方法。这将返回布尔值。

0

丑陋但有效。

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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接