我正在使用通过调用java.util.concurrent.ExecutorService
获得的Executors.newSingleThreadExecutor()
。此ExecutorService
有时可以停止处理任务,即使它尚未关闭并继续接受新任务而不会抛出异常。最终,它构建了足够的队列,我的应用程序关闭了OutOfMemoryError
个例外。
文档似乎表明这个单线程执行程序应该通过启动一个新的工作线程来更新任务处理错误,如果有必要替换已经死亡的那个。我错过了什么吗?
答案 0 :(得分:10)
听起来你有两个不同的问题:
1)你过度喂养工作队列。您不能只是将新任务填入队列,而不考虑任务执行者的消耗率。您需要弄清楚一些逻辑,以了解何时阻止新添加到工作队列。
2)任务线程中任何未捕获的异常都可以完全杀死该线程。发生这种情况时,ExecutorService会旋转一个新线程来替换它。但这并不意味着你可以忽略导致线程首先死亡的任何问题!找到那些未捕获的异常并抓住它们!
这只是一种预感(因为你的帖子中没有足够的信息来了解其他情况),但我不认为你的问题是任务执行者停止处理任务。我的猜测是它不会像你创建它们那样快速地处理任务。 (而且你的任务有时过早死亡的事实可能与问题正交。)
至少,这是我使用线程池和任务执行器的经验。
好的,这是另一种根据你的评论听起来可行的可能性(一切都会顺利运行几个小时,直到突然停止)......
您的任务线程之间可能存在罕见的死锁。大多数时候,你很幸运,而且僵局并没有表现出来。但偶尔会有两个或多个任务线程进入一个状态,在这个状态下,他们正在等待释放另一个线程持有的锁。此时,不再进行任务处理,并且您的工作队列将堆积起来,直到您收到OutOfMemoryError。
以下是我诊断该问题的方法:
消除任务线程之间的所有共享状态。首先,这可能需要每个任务线程制作所需的所有共享数据结构的防御性副本。一旦你完成了这个,就应该完全不可能遇到僵局。
此时,逐步重新引入共享数据结构,一次一个(具有适当的同步)。每次微小修改后重新运行您的应用程序以测试死锁。当您再次遇到崩溃情况时,请仔细查看共享资源的访问模式,并确定是否确实需要共享它。
就我而言,每当我编写使用线程池和执行程序处理并行任务的代码时,我总是试图消除这些任务之间的 ALL 共享状态。就应用程序而言,它们也可能是完全自治的应用程序。解决死锁是一种拖累,根据我的经验,消除死锁的最佳方法是每个线程都有自己的本地状态,而不是与其他任务线程共享任何状态。
祝你好运!答案 1 :(得分:3)
我的猜测是你的任务无限期地阻塞,而不是死亡。您是否有证据,例如任务结束时的日志声明,建议您的任务成功完成?
这可能是一个死锁,或者与一些阻塞的外部进程的交互。
答案 2 :(得分:1)
虽然你没有留下足够的细节以确定,但我要尝试的第一件事就是让你的任务在顶层捕获“异常”并记录消息。
我知道这似乎不对,但偶尔(取决于很多变量)我已经处理了代码,其中一个线程中发生的事情抛出异常并且它永远不会被记录,或者它只是不显示在控制台上 - 但“执行”代码退出了它的顶级循环或任何导致任务运行的代码。
我想我只是说,确保你的任务没有抛出异常。