以下情况会发生什么?
Timer t = new Timer();
t.schedule(...);
t = new Timer();
具体来说,当我给定一个新的 Timer 实例给 t 后,原先在 Timer t 上已经设置好的任务会发生什么?
Timer
对象都与一个后台进程相关联。即使您在程序中删除了对Timer
的所有引用,后台进程仍将继续运行(它持有自己对该对象的引用)。因此,该对象将不会受到垃圾回收的影响。与每个Timer对象相对应的是一个单独的后台线程,用于顺序执行计时器的所有任务...当最后一个Timer对象的活动引用消失并且所有未完成的任务已经执行完毕时,计时器的任务执行线程会正常终止(并成为垃圾回收的对象)。但是,这可能需要任意长的时间才能发生。
这将没有任何问题。唯一的问题是,如果您想要取消第一个计时器,您将无法取消它。
例如
private ScheduledExecutorService scheduler;
private AccurateScheduledRunnable periodic;
private ScheduledFuture<?> periodicMonitor;
private int taskPeriod = 30;
private SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
private SimpleDateFormat sdfHour = new SimpleDateFormat("HH");
. . .
scheduler = Executors.newSingleThreadScheduledExecutor();
periodic = new AccurateScheduledRunnable() {
private final int ALLOWED_TARDINESS = 200;
private int countRun = 0;
private int countCalled = 0;
@Override
public void run() {
countCalled++;
if (this.getExecutionTime() < ALLOWED_TARDINESS) {
countRun++;
dateNext = new java.util.Date();
dateLast = new java.util.Date();
long tme = dateNext.getTime();
tme += (taskPeriod * 60) * 1000;
dateNext.setTime(tme);
//System.out.println("");
//System.out.println("");
//System.out.println("Next Sheduled Time at : " + sdf.format(dateNext));
//System.out.println("Periodic Cycle In : " + (countRun) + "/" + countCalled + " at " + sdf.format(dateLast));
//ti.displayMessage(null, " Running Sheduled Task at " + sdf.format(new Date()), TrayIcon.MessageType.NONE);
distAppInfo();
}
}
};
periodicMonitor = scheduler.scheduleAtFixedRate(periodic, 0, taskPeriod, TimeUnit.MINUTES);
periodic.setThreadMonitor(periodicMonitor);
并实现了监视器,返回例如到下一个计划剩余的时间
long she = periodicMonitor.getDelay(TimeUnit.SECONDS);
和监视器
abstract class AccurateScheduledRunnable implements Runnable {
private ScheduledFuture<?> thisThreadsMonitor;
public void setThreadMonitor(ScheduledFuture<?> monitor) {
this.thisThreadsMonitor = monitor;
}
protected long getExecutionTime() {
long delay = -1 * thisThreadsMonitor.getDelay(TimeUnit.MILLISECONDS);
return delay;
}
}
计时器的API文档让我相信失去对计时器的引用不会对其产生影响。似乎任何已安排的任务仍然肯定会被执行。计时器实例不能被垃圾回收,应用程序也不能关闭,直到使用该计时器安排的最后一个任务完成执行。以下是文档摘录:
“当最后一个Timer对象的活动引用消失并且所有未完成的任务都已经执行完毕时,计时器的任务执行线程将优雅地终止(并成为垃圾回收的对象)。但是,这可能需要任意长的时间才能发生。默认情况下,任务执行线程不作为守护线程运行,因此它有可能阻止应用程序终止。如果调用者想要快速终止计时器的任务执行线程,则应调用计时器的cancel方法。”
这取决于您计划使用哪个Timer.schedule(..)方法。如果定时器被设置为重复执行,则将新的Timer实例分配给t不会导致垃圾回收,因为定时器线程将保持活动状态。如果您将定时器设置为一次性执行,则对象将被垃圾回收..至少文档是这样说的。