Java - 执行后不会删除Timer

时间:2016-08-30 11:30:12

标签: java timer timertask

我有一个启动计时器的应用程序,用于在用户操作上发送消息。在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探查器: enter image description here

是因为我使用的是静态方法还是应该自行销毁?

3 个答案:

答案 0 :(得分:7)

实际上,这里的定时器终止没有问题。您在探查器中看到的线程已经终止 - 它们左侧有一个白色方框,表示它们已经死了。

探查器显示在程序执行期间创建的所有线程,即使这些线程已经死亡并进行垃圾收集。

您可以通过执行以下操作轻松确认:创建TimerTask的子类,而不是lambda,它将执行相同的操作并重新定义其finalize()方法以打印某些内容。您将看到执行垃圾收集时,您的任务已完成。只有当线程被停止时才会发生这种情况,因为它是Thread类中唯一一个放弃对其RunnableTimerTask实现)的引用的地方。

另一种确认方法就是选择“直播主题”'从表格顶部的查看下拉列表中。

此外,我建议您将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();

如果一次有太多计划任务且这些任务不够小,您可以向执行程序添加多个线程。

答案 1 :(得分:2)

这是因为你需要手动配置计时器。

如果您使用java.util.Timer,则需要调用cancel方法来释放资源。

答案 2 :(得分:1)

您的计时器是使用非守护程序线程创建的,非守护程序线程可以阻止程序终止。你应该使用Timer的构造函数,它使用一个守护程序线程。

boolean daemon=true; Timer messagePrinter = new Timer(daemon);

但我会使用像Andrew Lygin建议的ExecutorService。