Java奇怪的线程终止

时间:2011-03-24 12:19:57

标签: java multithreading jvm

我有一个运行多个线程的系统 - 我的主线程只是检查是否有要完成的工作,如果有一些,它会调用将执行它的子线程(notifyAll())。之后,子线程只有wait(),直到有一些新任务。

实际上,线程系统运行可靠,但经过较长的运行时间(3-5h)后,某些子线程会在没有警告或错误的情况下死亡。他们只是一个接一个地退出 - 但是再次只有2个小时的时间范围。我已经使用jconsole来检查这种现象,哪些线程正在运行以及它们是如何消失的。

此外,主线程每秒执行一次,但子线程主要是wait()并且根本不常用(因为测试环境中没有那么多任务)。

我能想到的唯一原因是,JVM会关闭子线程,因为它们通常不够用?

我非常感谢你的帮助!

P.S。所有线程都没有定义为守护进程,主线程工作正常!

修改

感谢您的回答,但我确实使用了这个循环。

public void addTask (Task in_task) throws InterruptedException {
        synchronized (tasks) {
              while (tasks.size() == MAXIMUM_NUMBER_OF_TASKS) {
                   tasks.wait();
              }
              tasks.offer(in_task);
              tasks.notifyAll();
        }
}

我使用这个循环,因此只会执行一些特殊的任务。

4 个答案:

答案 0 :(得分:5)

Object.wait()的文档说:

  

在一个参数版本中,中断和虚假唤醒是可能的,并且此方法应始终在循环中使用:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
 }

也许你没有遵循这个建议并得到虚假的唤醒或中断?

答案 1 :(得分:2)

您可以使用java.util.concurrent.ThreadPoolExecutor而不是编写自己的多线程任务执行解决方案。无论你是否能够修复这个bug,这都可能是一个好主意。

答案 2 :(得分:1)

我建议使用其中一个Executors来管理您的任务。您在其中一个子线程中丢失可能的错误或异常的可能性较小,因此它应该可以帮助您调试程序。当您调用Future时,子线程中发生的任何异常都将存储在ExecutionException对象中,并作为Future#get()重新生成。

List<Future<Void>> taskResults = new ArrayList<Future<Void>>();
ExecutorService es = Executors.newFixedThreadPool(NUMBER_OF_THREADS);

while(!finished){
  //say you wait (blocking) for a new task here
  Callable<Void> task = getNextTask();

  //put the task into the pool
  Future<Void> result = es.submit(task);
  taskResults.add(result);
}

//3 hours later, set `finished` to true

//at the end check that no exceptions were thrown
for(Future<Void> result : taskResults){
  try{
    result.get();
  }catch(ExecutionException e){
    //there was an error
    e.getCause().printStackTrace();
  }catch(InterruptedException e){
    //irrelevant
  }
}

通常,java.util.concurrent中的内容可以帮助您编写更强大的多线程应用程序,而不必诉诸Object#wait()和其他并发原语(当然,除非您正在学习)。 / p>

答案 3 :(得分:0)

尝试在每个线程上设置未捕获的异常处理程序。 Thread上有一个setUncaughtExceptionHandler()函数。实现UncaughtExceptionHandler接口并打印异常。

一般的想法,但不要使用匿名类/方法:

thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
  public void uncaughtException(Thread t, Throwable e)
  {
    e.printStackTrace();
  }
});