我想以某种方式记录每次调用Thread.interrupt()
时,记录哪个线程发出了调用(及其当前堆栈)以及识别有关哪个线程被中断的信息。
有办法做到这一点吗?在搜索信息时,我看到有人提到了实施安全管理器的可能性。这是可以在运行时完成的事情(例如,在Applet或Web Start客户端中),还是需要使用已安装的JVM来实现此目的?
或者有更好的方法吗?
答案 0 :(得分:10)
作为一个快速的黑客,这比我想象的更容易做到很多。由于这是一个快速入侵,我没有做任何事情,比如在取消引用数组之前确保堆栈跟踪足够深,等等。我在我签名的Applet的构造函数中插入了以下内容:
log.info("Old security manager = " + System.getSecurityManager());
System.setSecurityManager(new SecurityManager() {
@Override
public void checkAccess(final Thread t) {
StackTraceElement[] list = Thread.currentThread().getStackTrace();
StackTraceElement element = list[3];
if (element.getMethodName().equals("interrupt")) {
log.info("CheckAccess to interrupt(Thread = " + t.getName() + ") - "
+ element.getMethodName());
dumpThreadStack(Thread.currentThread());
}
super.checkAccess(t);
}
});
和dumpThreadStack
方法如下:
public static void dumpThreadStack(final Thread thread) {
StringBuilder builder = new StringBuilder('\n');
try {
for (StackTraceElement element : thread.getStackTrace()) {
builder.append(element.toString()).append('\n');
}
} catch (SecurityException e) { /* ignore */ }
log.info(builder.toString());
}
当然,我永远不会把它留在生产代码中,但它足以让我确切地告诉我哪个线程导致interrupt()
我没想到。也就是说,使用此代码,我会在每次调用Thread.interrupt()
时获得堆栈转储。
答案 1 :(得分:4)
在尝试过于狂野之前,您是否考虑过使用Java debugging API?我认为在Thread.interrupt()上捕获MethodEntryEvents会做到这一点。
答案 2 :(得分:2)
我会查看AspectJ及其包装方法调用的功能。 interrupt()
方法周围的execution pointcut应该有帮助。
请注意,由于您正在寻找拦截Java系统方法调用(而不是您的应用程序代码),因此上述可能不适合。 This thread似乎暗示它是可能的,但请注意他创建了一个编织 rt.jar。
答案 3 :(得分:1)
正如其他人所说的......如果它是一次性的事情,JVMTI可能是最核心的方式。但是,同样有趣的是使用asm库和instrumentation API来创建一个代理,该代理插入对在Thread.interrupt()调用之前创建的静态方法的调用(或者可能改变Thread.interrupt( )做同样的方法,我想你可以这样做。)
两者都需要一些时间来学习,但是使用起来非常有趣,一旦掌握了它,你可以将它们用于各种有趣的事情:-) 我现在没有任何好的片段可以粘贴到这里但是如果你围绕ASM进行搜索并且可能会看到JIP对ASM的一些创造性使用我认为你会找到灵感。
答案 4 :(得分:0)
您也可以尝试使用JMX:
ManagementFactory.getThreadMXBean().getThreadInfo(aThreadID)
使用您可以记录的ThreadInfo对象:
修改强>
使用getAllThreadIds()以获取活动线程ID列表:
long[] ids = ManagementFactory.getThreadMXBean().getAllThreadIds();