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