在Java中有没有办法记录*每个* Thread中断?

我想以某种方式记录每次调用Thread.interrupt() ,记录哪个Thread发出了调用(及其当前堆栈)以及识别有关哪个Thread被中断的信息。

有没有办法做到这一点? 在搜索信息时,我看到有人提到了实施安全管理器的可能性。 这是可以在运行时完成的事情(例如,在Applet或Web Start客户端中),还是需要使用已安装的JVM来执行此操作?

或者有更好的方法吗?

作为一个快速的黑客,这比我想象的要容易得多。 由于这是一个快速入侵,我没有做任何事情,比如在取消引用数组之前确保堆栈跟踪足够深,等等。我在我签名的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()都会得到一个堆栈转储。

在尝试任何过于疯狂的事情之前,您是否考虑过使用Java调试 API ? 我认为在Thread.interrupt()上捕获MethodEntryEvents会做到这一点。

Eeek,这是旧界面,您还应该检查新的JVM工具 界面 。

我会看看AspectJ及其包装方法调用的function。 在这里, interrupt()方法的执行切入点应该有所帮助。

请注意,由于您要拦截Java系统方法调用(而不是您的应用程序代码),因此上述内容可能不合适。 这个主题似乎暗示它是可能的,但请注意他创建了一个编织的 rt.jar。

正如其他人所说的……如果它是一次性的事情,JVMTI可能是最核心的方式。 但是,同样有趣的是使用asm库和instrumentation API来创建一个代理,该代理插入对您在Thread.interrupt()调用之前创建的静态方法的调用(或者可能改变Thread.interrupt( )方法做同样的事情,我想你可以做到这一点)。

两者都需要一些时间来学习,但是使用起来非常有趣,一旦掌握它,你可以将它们用于各种有趣的事情:-)我真的没有任何好的片段可以粘贴在这里现在,但如果你谷歌围绕ASM,也许看看JIP对ASM的一些创造性使用,我想你会找到灵感。

JIP: Java Interactive Profiler

您也可以尝试使用JMX:

 ManagementFactory.getThreadMXBean().getThreadInfo(aThreadID) 

使用ThreadInfo对象,您可以记录:

  • 线程的堆栈跟踪
  • 一般用户信息,如姓名,状态等
  • 等等

编辑

使用getAllThreadIds()来获取活动线程ID的列表:

 long[] ids = ManagementFactory.getThreadMXBean().getAllThreadIds();