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 中唯一删除对其 RunnableTimerTask 实现)的引用的地方。

另一种确认方法是从 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。