我有代码可以安排一次性任务来执行,并一遍又一遍地执行此操作。它看起来像这样。
public static void main(String[] args)
{
while(true)
{
....
TimerTask closeTask = new CloseTask(cli);
Timer timer = new Timer(true);
timer.schedule(closeTask, (long) (iPeriod * 60 * 1000));
...
}
}
public class CloseTask extends TimerTask
{
Client client;
CloseTask(Client in_client)
{
client = in_client;
}
public void run()
{
try
{
for(int iRetries = 0; state == OPEN; iRetries++)
{
logger.log_trade_line_grablock( "Thread " + Thread.currentThread().getId() + ": About to send message", true, true, true, true, true);
client.send_mesg("close");
logger.log_trade_line_grablock( "Waiting 5 seconds before retrying ", true, true, true, true, true);
Thread.sleep(5000);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
CloseTask
类中 run()
方法的目的是循环,直到state
变量从OPEN
状态更改为其他状态。但是,计时器线程间歇性地消失了,而state
仍然等于 OPEN
,我通过每 5 分钟打印出当前正在运行的线程的所有线程 ID 来知道这一点。
所以我的问题:1)我能想到的唯一解释是CloseTask
对象抛出未捕获的异常。这是对的吗?2)如果1)是正确的,为什么我的try catch块没有捕获这些异常?3)如果1)是正确的,有没有办法捕获这些未捕获的异常?
感谢您对此问题的任何见解。
您正在创建一个Timer
实例,但不确定它不会被垃圾回收。
从文档中:
在对 Timer 对象的最后一个实时引用消失并且所有未完成的任务都已完成执行后,计时器的任务执行线程将正常终止(并受到垃圾回收的影响)。
所以基本上,你需要保留对你创建的Timer
的引用,而不仅仅是使用局部变量。
您传入的布尔值告诉创建的线程是否会daemon
。 如果是守护程序,则一旦所有非守护程序线程完成,线程将停止。 由于应用程序中运行的唯一非守护程序线程是主线程,因此在 main 方法完成后,它将立即停止。
正如 Jon Skeet 所提到的,如果没有活动线程引用计时器并且任务完成,则会完成一些完成操作,但如果它是守护程序并且 main 方法完成,它可能不会正常退出。 继续文档
。但是,这可能需要任意长时间才能发生。默认情况下,任务执行线程不作为守护程序线程运行,因此它能够防止应用程序终止。如果调用方想要快速终止计时器的任务执行线程,则调用方应调用计时器的 cancel 方法。
回答您的问题
我能想到的唯一解释是 CloseTask 对象抛出未捕获的异常。这是对的吗?
如果 JVM 杀死了一个非守护进程线程,它不会抛出任何异常。 所以你不会真正知道它发生了。