2016-08-30 43 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。