2016-08-30 32 views
9

我有一个应用程序启动一个计时器来在用户操作上显示一条消息。在JDK profiler中,似乎所有其他线程在被GC执行后被删除(我猜),但创建的定时器没有被删除。那里会发生什么?Java - 计时器在执行后没有被移除

我的定时器:

/** 
* @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

难道是因为我使用的是静态方法还是应该摧毁它自己?

回答

7

其实,你在这里定时器终止没问题。你在profiler中看到的线程已经被终止–他们在左边有一个白色框表示它们已经死了。

分析器显示程序执行过程中创建的所有线程,即使这些线程已经死了并且垃圾收集。

您可以轻松地确认通过执行以下操作:而不是一个拉姆达的,创造的TimerTask一个子类,它会做同样的,重新定义其finalize()方法来打印一些东西。你会看到当垃圾收集被执行时,你的任务已经完成。它只有在线程停止时才会发生,因为它是Thread类中的唯一地方,它将引用删除到其Runnable(其实现为TimerTask)。

另一种确认方法是从表格顶部的视图下拉列表中选择“实时线程”。

另外,我建议你用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(); 

,如果你有一次太多的计划任务和这些任务都是不小的话,你可以添加多个线程的执行。

+0

我不确定,但很高兴知道,反正,我用javaFX的时间轴,而不是(至少对我来说)更好 –

2

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

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

+0

你能告诉如何? –

+0

name_of_timer.cancel(); ? –

+0

是的。在这种情况下'messagePrinter.cancel();' – talex

1

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

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

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