我该从哪里开始调查无法结束的Java进程?

10
我有一个Java应用程序没有结束。主方法已经完成但线程仍然活跃,该应用程序无法结束。问题是,似乎没有监视器锁/等待,所以我不知道为什么它无法结束。根据Eclipse的说法,我剩下了两个非Daemon线程。其中一个标记为[DestroyJavaVM](看起来很有希望!),而另一个似乎被阻塞在 Unsafe.park(boolean,long) 中。我应该从哪里开始调查呢?
第二个线程的简略堆栈跟踪如下:
   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() 

Unsafe.park()线程的完整堆栈跟踪是什么? - Mike Tunnicliffe
Unsafe.park(boolean, long) -> LockSupport.park(Object) -> AbstractQueuedSynchronizer$ConditionObject.await() -> LinkedBlockingQueue<E>.take() -> ThreadPoolExecutor.getTask() -> ThreadPoolExecutor$Worker.run() -> Thread.run() Unsafe.park(boolean, long) -> LockSupport.park(Object) -> AbstractQueuedSynchronizer$ConditionObject.await() -> LinkedBlockingQueue<E>.take() -> ThreadPoolExecutor.getTask() -> ThreadPoolExecutor$Worker.run() -> Thread.run() - JenFallow
我已经将您的评论编辑到问题中,因为在代码块中更容易阅读,并且它本身构成了问题的重要部分。 - Andrzej Doyle
5个回答

1

+1:shutdown() 是执行此操作的规范方式 - 守护线程可以防止此问题,但很可能不是所需的,并且可能会导致以后出现问题。 - Andrzej Doyle

0
不确定应用程序有多大,但我会检查您创建的所有线程,并确保它们的运行方法在应用程序执行完成时被清理退出。在某个线程中,您可能有以下代码:
public void run() {
    while(true) { //"true" or some condition that never gets a chance to be false
        //do thread related work
    }
}

0

线程转储和调试器可能是我的猜测。


0

Unsafe.park,尽管听起来很可怕,但通常被各种阻塞调用使用(特别是在新的java.util.concurrent包中)。

如果你向下看几个帧,你会看到类似于java.util.concurrent.LinkedBlockingQueue.take(即一些JDK库类),然后是类似于com.example.myapp.MyClass.getNextJob(即使用库类的你的类)。

如果我要猜测的话,我会说你正在进行某种永久阻塞的调用,因此当没有更多内容返回时,该线程就会坐在那里等待“下一个”项目。你可以通过设置某种“完成”标志来解决这个问题,然后中断等待线程或给阻塞调用设置超时,让它检查标志。根据你的代码,这两种方法或其他替代方法都可能可行,但希望这足以让你开始。

编辑:在看到堆栈跟踪后,finnw正确指出您需要关闭执行器服务。


0

你的任务因为等待队列中的数据而被阻塞。Take 操作没有与之关联的超时时间。

在创建线程时,保持对任务线程的引用。在关闭时,调用线程的 interrupt 方法。你可能还需要修改调用 take 的工作处理循环,以便在捕获 InterruptedException 时退出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接