Есть ли способ в Java, чтобы регистрировать * каждое * прерывание потока? - PullRequest
6 голосов
/ 28 апреля 2009

Я хотел бы как-нибудь регистрировать каждый раз, когда вызывается Thread.interrupt(), регистрируя, какой поток совершил вызов (и его текущий стек), а также идентифицируя информацию о том, какой поток прерывается.

Есть ли способ сделать это? В поисках информации я видел, как кто-то упоминал о возможности реализации менеджера безопасности. Это можно сделать во время выполнения (например, в апплете или в клиенте Web Start), или для этого нужно установить установленную JVM?

Или есть лучший способ сделать это?

Ответы [ 5 ]

10 голосов
/ 29 апреля 2009

Как быстрый взлом, это было лот легче сделать, чем я думал. Поскольку это быстрый взлом, я не делал таких вещей, как обеспечение достаточной глубины трассировки стека перед разыменованием массива и т. Д. Я вставил следующее в конструктор моего подписанного апплета:

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().

4 голосов
/ 28 апреля 2009

Прежде чем пытаться что-то слишком дикое, вы рассматривали возможность использования Java отладки API ? Я думаю, что захват метода MethodEntryEvents в Thread.interrupt () сделает это.

Eeek, это старый интерфейс, вы также должны проверить новый JVM Tool Интерфейс .

2 голосов
/ 28 апреля 2009

Я бы посмотрел на AspectJ и его возможности для переноса вызовов методов. выполнение pointcut вокруг interrupt() метода должно помочь здесь.

Обратите внимание, что, поскольку вы пытаетесь перехватить вызов системного метода Java (в отличие от кода вашего приложения), вышеприведенный может не подойти. Эта тема , кажется, предполагает, что это возможно, но обратите внимание, что он создал тканый rt.jar.

1 голос
/ 28 апреля 2009

Как уже говорили другие ... Если это разовая вещь, JVMTI, вероятно, самый сложный путь. Тем не менее, также интересно использовать библиотеку asm и API инструментария для создания агента, который вставляет вызов статического метода, созданного вами непосредственно перед вызовом Thread.interrupt () (или, возможно, изменяет Thread.interrupt ( ) способ сделать то же самое, я думаю, вы можете сделать это).

И то, и другое требует некоторого времени для изучения, но работать с ним довольно весело, и как только вы овладеете им, вы сможете использовать их в будущем для самых разных забавных вещей :-) У меня нет хороших фрагментов для вставки прямо сейчас, но если вы заглянете в Google для ASM и, возможно, посмотрите на JIP для творческого использования ASM, я думаю, вы найдете вдохновение.

JIP: Java Interactive Profiler

0 голосов
/ 28 апреля 2009

Вы можете попробовать также с JMX:

ManagementFactory.getThreadMXBean().getThreadInfo(aThreadID)

с объектом ThreadInfo , в который можно войти:

  • трассировка стека потока
  • общая полезная информация, такая как имя, статус и т. Д.
  • и т.д.

EDIT

используйте getAllThreadIds () для получения списка идентификаторов активных потоков:

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