Есть ли в Java какой-либо способ регистрировать * каждое * прерывание потока?
-
18-09-2019 - |
Вопрос
Я хотел бы каким-то образом регистрироваться каждый раз Thread.interrupt()
вызывается, регистрируя, какой поток выдал вызов (и его текущий стек), а также идентифицируя информацию о том, какой поток прерывается.
Есть ли способ сделать это?В поисках информации я увидел, как кто-то упоминал о возможности внедрения менеджера безопасности.Это что-то, что можно сделать во время выполнения (например, в апплете или клиенте Web Start), или для этого вам нужно использовать установленную JVM?
Или есть лучший способ сделать это?
Решение
В качестве быстрого взлома, это был много сделать это легче, чем я думал, что это будет.Поскольку это быстрый взлом, я не делал таких вещей, как обеспечение достаточной глубины трассировки стека перед разыменованием массива и т.д.Я вставил следующее в конструктор моего подписанного апплета:
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?Я бы подумал, что захват MethodEntryEvents в Thread.interrupt() сделает это.
Ик, это старый интерфейс, тебе также следует проверить наличие нового Инструмент JVM Интерфейс.
Я бы посмотрел на Аспект J и его возможности для переноса вызовов методов.Ан сокращение точки выполнения вокруг interrupt()
здесь должен помочь метод.
Обратите внимание, что, поскольку вы хотите перехватить вызов системного метода Java (в отличие от кода вашего приложения), приведенное выше мочь не подходит. Этот поток кажется, предполагают, что это возможно, но обратите внимание, что он создал сплетенный rt.jar .
Как говорили другие...Если это одноразовая вещь, JVMTI, вероятно, самый хардкорный способ.Однако не менее интересно было бы использовать библиотеку asm и API инструментария для создания агента, который вставляет вызов статического метода, созданного вами непосредственно перед вызовом Thread.interrupt() (или, возможно, изменяет метод Thread.interrupt(), чтобы сделать то же самое, я думаю, вы можете это сделать).
Изучение обоих требует некоторого времени, но работать с ними довольно забавно, и как только вы овладеете ими, вы сможете использовать их для всевозможных забавных вещей в будущем :-) На самом деле у меня нет хороших фрагментов для вставки сюда прямо сейчас, но если вы погуглите в поисках ASM и, возможно, заглянете в JIP для творческого использования ASM, я думаю, вы найдете вдохновение.
Вы могли бы попробовать также с JMX:
ManagementFactory.getThreadMXBean().getThreadInfo(aThreadID)
с помощью Информация о потоке объект, который вы можете зарегистрировать:
- трассировка стека потока
- общая полезная информация, такая как имя, статус и т. Д
- и т.д.
Редактировать
используйте getAllThreadIds(), чтобы получить список идентификаторов текущего потока:
long[] ids = ManagementFactory.getThreadMXBean().getAllThreadIds();