У меня есть JAVA-приложение, которое не заканчивается. Концы основного метода, но потоки остаются активными, и приложение не заканчивается. Вещь, кажется, нет никаких блокировок монитора / ожидает, таким образом, я не вижу, почему она не заканчивается. Согласно Eclipse, меня оставляют с двумя потоками недемона. Каждый маркирован [DestroyJavaVM] (выглядит обнадеживающим!) и другой, кажется, заблокирован в Unsafe.park(boolean, long)
. Как / где я должен начать исследовать это?
Сокращенный stacktrace второго потока:
Unsafe.park(boolean, long)
at LockSupport.park(Object)
at AbstractQueuedSynchronizer$ConditionObject.await()
at LinkedBlockingQueue<E>.take()
at ThreadPoolExecutor.getTask()
at ThreadPoolExecutor$Worker.run()
at Thread.run()
Не уверен, насколько велико приложение, но я бы проверил все созданные вами потоки и убедился, что их методы запуска чисто завершаются по окончании выполнения приложения. Где-то, внутри потока, у вас может быть код следующего содержания:
public void run() {
while(true) { //"true" or some condition that never gets a chance to be false
//do thread related work
}
}
Ваша задача заблокирована в ожидании данных из очереди. У дубля нет связанного с ним таймаута.
Сохраните ссылку на поток вашей задачи при его создании. При завершении работы вызовите метод прерывания потока. Возможно, вам также потребуется изменить цикл обработки работы, который вызывает take, чтобы он завершался, когда будет пойман InterruptedException.
Чтобы завершить работу вашего потока ExecutorService
, необходимо выполнить одно из двух действий:
ThreadFactory
, который создает потоки демона ( ThreadFactoryBuilder
класс из Guava упростит это.) shutdown ()
на вашем ExecutorService
как часть завершения работы приложения (например, в конце вашего метода main
.) Unsafe.park
, несмотря на страшно звучащее название, обычно используется всеми видами блокирующих вызовов (особенно в новом (иш) пакете java.util.concurrent
).
Если вы посмотрите на несколько кадров дальше вниз по стеку, вы увидите что-то вроде java.util.concurrent.LinkedBlockingQueue.take
(т.е. какой-то библиотечный класс JDK), за которым следует что-то вроде com.example.myapp.MyClass.getNextJob
(т.е. ваш класс, использующий библиотечный класс).
Если бы я рискнул предположить, я бы сказал, что вы делаете какой-то вызов, который блокируется навсегда - и поэтому, когда больше нечего возвращать, этот поток просто сидит и ждет "следующего" элемента. Вы можете решить эту проблему, установив какой-то флаг "завершено", а затем либо прервать ожидающий поток, либо дать блокирующему вызову таймаут, заставив его проверить флаг. В зависимости от вашего кода любой из этих или альтернативных вариантов может быть осуществим, но, надеюсь, этого достаточно, чтобы начать.
Edit: после просмотра трассировки стека, finnw прав, что вам нужно выключить службу исполнителя.