Убить застрявший поток на работающей виртуальной машине (экземпляр JBoss) в Java?

ошибка в сторонней библиотеке вызывает бесконечный цикл в рабочем потоке на моем экземпляре JBoss. Знаете ли вы способ убить этот «зависший» поток без перезапуска сервера? Мы хотели бы иметь возможность восстанавливаться после этого до тех пор, пока не будет развернуто исправление, желательно без перезапуска.

Я видел, как несколько человек упомянули об использовании Thread.interrupt() - если Я должен был закодировать свой собственный MBean, как мне получить дескриптор рассматриваемого потока, чтобы прервать его?

Обновление: не удалось решить ни одним из этих методов. Я наткнулся на другую тему, посвященную той же проблеме, в которой была ссылка на то, почему Thread.stop() устарел. Кто-то еще задал аналогичный вопрос с аналогичными результатами. Кажется, что более сложные контейнеры должны обеспечивать такой механизм работоспособности, но я предполагаю, что их руки связаны с JVM.


person cwash    schedule 21.01.2011    source источник


Ответы (4)


У меня была похожая ошибка (бесконечный цикл) в сторонней библиотеке. В итоге я сам применил исправление (ожидая, пока люди из сторонней библиотеки исправят свой беспорядок), а затем поместил измененный .class в свой .war, убедитесь, что он загружается перед поддельным .class (поддельный находится внутри поддельного стороннего .jar).

Это нехорошо, но работает, см. мой вопрос здесь:

Порядок загрузки классов из файла .war

Я имею в виду следующее: если вам приходится ждать, пока люди, ответственные за стороннюю библиотеку с ошибками, исправят свои вещи, вы потенциально можете ждать очень долго. Мы не могли себе этого позволить. Нам нужно было исправить как можно скорее. В итоге мы применили патч/хак к их коду.

Например, вы можете добавить логическую проверку внутри бесконечного цикла, а затем принудительно завершить цикл, когда вы хотите, чтобы фиктивный поток «умер».

Обратите внимание, что я не использовал устаревший метод Thread stop() уже десять лет, и я действительно не хотел использовать его в приведенном выше случае.

person SyntaxT3rr0r    schedule 21.01.2011
comment
Согласен относительно: не дожидаясь, пока сторонние разработчики исправят это, я говорил только о том, чтобы подождать в очень краткосрочной перспективе (следующие несколько дней), чтобы наш патч был проверен посредством тестирования. Спасибо за варианты программного исправления, похоже, хорошие подходы - я действительно ищу встроенный вариант восстановления. Не могу поверить, что нет способа убить хотя бы один поток, который, как вы знаете, является злокачественным! - person cwash; 21.01.2011

Я полагаю, что самое сложное — определить висящую нить. Вы не предоставляете никакой информации об этом, но, возможно, вы можете создать некоторые правила для имени потока или его текущей трассировки стека.

Если вы можете идентифицировать поток по его имени, я бы получил все потоки в виртуальной машине, получив свою собственную группу потоков с помощью Thread.currentThread().getThreadGroup(), а затем поднялся по иерархии групп потоков, вызвав getParent() в группе потоков, пока он не вернет null. Теперь у вас есть группа потоков верхнего уровня. Теперь вы можете заполнить предварительно выделенный массив всеми потоками, используя метод enumerate(Thread[] list) в группе потоков верхнего уровня.

Если вам в любом случае нужны трассировки стека для идентификации потока, вы также можете использовать статический служебный метод Map<Thread,StackTraceElement[]> Thread.getAllStackTraces() для получения всех потоков. Однако вычисление трассировки стека довольно дорого, поэтому это может быть не лучшим решением, если они вам на самом деле не нужны.

После определения потока вы должны вызвать для него метод stop(). Прерывание не поможет, если только реализация работающего кода фактически не оценивает флаг прерывания потока и не ведет себя так, как вы ожидаете. Не то чтобы метод stop() устарел и что его использование может иметь много забавных побочных эффектов. Вы можете найти более подробную информацию в документации по API.

person jarnbjo    schedule 21.01.2011
comment
Я определил это через ThreadDump в VisualVM. Я точно знаю, что это такое, но получить это в коде — другое дело. Метод, который вы предлагаете, чтобы получить threadGroup, а затем пройтись, звучит осуществимо, но мне нужен фактический дескриптор экземпляра потока, чтобы вызвать для него stop() или interrupt(). - person cwash; 21.01.2011
comment
@cwash — метод enumerate возвращает фактические экземпляры потоков. переданный массив заполняется всеми найденными экземплярами Thread. если вы знаете идентификатор потока, вы можете просмотреть этот массив в поисках потока с соответствующим идентификатором. Обратите внимание, что метод enumerate() имеет странную семантику (он не сообщает вам о переполнении), поэтому заставить его работать сложно. обратите внимание, вы можете использовать ThreadGroup.getActiveCount() для первого предположения о размере массива. - person jtahlborn; 22.01.2011
comment
@cwash — см. несколько примеров здесь: nadeausoftware.com/articles/2008/04/ - person jtahlborn; 22.01.2011

Вы можете использовать обескураженный метод myThread.stop(). Но тогда очень вероятно, что Thread все еще ссылается там, поэтому вам следует использовать некоторую магию отражения, чтобы удалить все ссылки на этот поток из компонентов, содержащих его.

Как найти нить? Используйте Thread.getThreadGroup() и ThreadGroup.getThreadGroup(), чтобы перейти к корневой группе ThreadGroup(), а затем используйте функции iterate() для прохождения всех потоков.

person Daniel    schedule 21.01.2011
comment
Звучит осуществимо, но я думаю, мне нужно попробовать. Не знаете ничего, что уже ищет ветку по названию? Вы когда-нибудь использовали iterate() для сортировки потоков? - person cwash; 21.01.2011

Попробуйте мой jkillthread, который пытается сделать что-то подобное.

person Jesse Glick    schedule 05.11.2013