Java - 计时器在执行后未被删除
Java - Timer is not being removed after execution
我有一个应用程序可以启动计时器以在用户操作时显示消息。在 JDK 分析器中,似乎所有其他线程在 GC 执行后都被删除(我猜),但创建的计时器没有被删除。那里会发生什么?
我的计时器:
/**
* @param owner
* @param added
*/
public static void splashParentWithAnimation(AnchorPane owner, Parent added,double posX,double posY) {
// addParentWithAnimation(owner, added);
owner.getChildren().add(added);
AnchorPane.setLeftAnchor(added, posX);
AnchorPane.setTopAnchor(added, posY);
FadeTransition ft1 = new FadeTransition(Duration.millis(300), added);
ft1.setFromValue(0.0);
ft1.setToValue(1.0);
ft1.play();
Timer messagePrinter = new Timer();
messagePrinter.schedule(new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> {
if (!owner.getChildren().contains(added))
return;
FadeTransition ft1 = new FadeTransition(Duration.millis(300), added);
ft1.setFromValue(1.0);
ft1.setToValue(0.0);
ft1.play();
ft1.setOnFinished((e) -> {
if (owner.getChildren().contains(added))
owner.getChildren().remove(added);
});
});
}
}, 1000);
}
JDK 探查器:
是因为我用的是静态方法还是应该自己销毁?
因为需要手动配置timer
如果你使用java.util.Timer
你需要调用cancel
方法来释放资源。
其实你这里的定时器终止没有问题。您在探查器中看到的线程已经终止——它们的左侧有一个白框,表明它们已死。
探查器显示在程序执行期间创建的所有线程,即使这些线程已经死亡并被垃圾收集。
您可以通过执行以下操作轻松确认:创建一个 TimerTask
的子 class 而不是 lambda,它会做同样的事情并重新定义它的 finalize()
方法来打印某物。您会看到,当执行垃圾回收时,您的任务就完成了。它只有在线程停止时才会发生,因为它是 Thread
class 中唯一删除对其 Runnable
(TimerTask
实现)的引用的地方。
另一种确认方法是从 table.
顶部的视图下拉列表中 select 'Live Threads'
此外,我建议您用 Timer
代替更好的东西。每次需要延迟某个任务时都创建一个线程太浪费了。看看ScheduledThreadPoolExecutor
,它似乎更适合你的任务:
// Create a shared executor with a single thread
private final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
// Instead of creating a Timer, schedule the task
executor.schedule(() -> {
// Do what you need here
}, 1, TimeUnit.SECONDS);
// Don't forget to terminate the scheduler when you don't need it anymore
scheduler.terminate();
如果您一次有太多计划任务并且这些任务不够小,您可以向执行器添加多个线程。
您的计时器是使用非守护线程创建的,非守护线程可以阻止您程序的终止。您应该使用 Timer 的构造函数,使其使用守护线程。
boolean daemon=true;
Timer messagePrinter = new Timer(daemon);
但我会像 建议的那样使用 ExecutorService。
我有一个应用程序可以启动计时器以在用户操作时显示消息。在 JDK 分析器中,似乎所有其他线程在 GC 执行后都被删除(我猜),但创建的计时器没有被删除。那里会发生什么?
我的计时器:
/**
* @param owner
* @param added
*/
public static void splashParentWithAnimation(AnchorPane owner, Parent added,double posX,double posY) {
// addParentWithAnimation(owner, added);
owner.getChildren().add(added);
AnchorPane.setLeftAnchor(added, posX);
AnchorPane.setTopAnchor(added, posY);
FadeTransition ft1 = new FadeTransition(Duration.millis(300), added);
ft1.setFromValue(0.0);
ft1.setToValue(1.0);
ft1.play();
Timer messagePrinter = new Timer();
messagePrinter.schedule(new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> {
if (!owner.getChildren().contains(added))
return;
FadeTransition ft1 = new FadeTransition(Duration.millis(300), added);
ft1.setFromValue(1.0);
ft1.setToValue(0.0);
ft1.play();
ft1.setOnFinished((e) -> {
if (owner.getChildren().contains(added))
owner.getChildren().remove(added);
});
});
}
}, 1000);
}
JDK 探查器:
是因为我用的是静态方法还是应该自己销毁?
因为需要手动配置timer
如果你使用java.util.Timer
你需要调用cancel
方法来释放资源。
其实你这里的定时器终止没有问题。您在探查器中看到的线程已经终止——它们的左侧有一个白框,表明它们已死。
探查器显示在程序执行期间创建的所有线程,即使这些线程已经死亡并被垃圾收集。
您可以通过执行以下操作轻松确认:创建一个 TimerTask
的子 class 而不是 lambda,它会做同样的事情并重新定义它的 finalize()
方法来打印某物。您会看到,当执行垃圾回收时,您的任务就完成了。它只有在线程停止时才会发生,因为它是 Thread
class 中唯一删除对其 Runnable
(TimerTask
实现)的引用的地方。
另一种确认方法是从 table.
顶部的视图下拉列表中 select 'Live Threads'此外,我建议您用 Timer
代替更好的东西。每次需要延迟某个任务时都创建一个线程太浪费了。看看ScheduledThreadPoolExecutor
,它似乎更适合你的任务:
// Create a shared executor with a single thread
private final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
// Instead of creating a Timer, schedule the task
executor.schedule(() -> {
// Do what you need here
}, 1, TimeUnit.SECONDS);
// Don't forget to terminate the scheduler when you don't need it anymore
scheduler.terminate();
如果您一次有太多计划任务并且这些任务不够小,您可以向执行器添加多个线程。
您的计时器是使用非守护线程创建的,非守护线程可以阻止您程序的终止。您应该使用 Timer 的构造函数,使其使用守护线程。
boolean daemon=true;
Timer messagePrinter = new Timer(daemon);
但我会像