2016-08-30 2 views
9

Ich habe eine Anwendung, die einen Timer startet, um eine Nachricht auf Benutzeraktionen zu übertragen. Im JDK-Profiler scheint es, dass alle anderen Threads nach der Ausführung durch GC entfernt werden (ich denke mal), aber die erstellten Timer werden nicht entfernt. Was könnte dort passieren?Java - Timer wird nicht nach der Ausführung entfernt

meine Timer:

/** 
* @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 Profiler: enter image description here

Ist es, weil ich eine statische Methode verwenden oder soll ich es selbst zerstören?

Antwort

7

Eigentlich haben Sie hier kein Problem mit Timer Kündigung. Die Threads, die Sie im Profiler sehen, sind bereits beendet – sie haben ein weißes Feld auf der linken Seite, die anzeigt, dass sie tot sind.

Der Profiler zeigt alle Threads, die während der Programmausführung erstellt wurden, auch wenn diese Threads bereits tot und Garbage-Collected sind.

Sie können dies einfach bestätigen, indem Sie Folgendes tun: Erstellen Sie statt eines Lambda eine Unterklasse von TimerTask, die dasselbe tut und ihre finalize() Methode neu definiert, um etwas zu drucken. Sie werden feststellen, dass bei der Durchführung von Garbage Collections Ihre Aufgaben abgeschlossen sind. Es kann nur passieren, wenn Threads gestoppt werden, weil es der einzige Platz in der Thread Klasse ist, wo es den Verweis auf seinen Runnable (welcher TimerTask implementiert) fallen lässt.

Eine andere Möglichkeit, dies zu bestätigen, ist nur "Live Threads" aus der Dropdown-Liste "Ansicht" am Anfang der Tabelle auszuwählen.

Zusätzlich würde ich Ihnen empfehlen, Timer für etwas besseres zu ersetzen. Es ist zu verschwenderisch, jedes Mal einen Thread zu erstellen, wenn Sie eine Aufgabe verschieben müssen. Werfen Sie einen Blick auf ScheduledThreadPoolExecutor, so scheint es viel besser geeignet für Ihre Aufgabe:

// 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(); 

Sie können zum Testamentsvollstrecker mehr als ein Thread hinzufügen, wenn Sie auf einmal zu viele geplante Aufgaben haben und diese Aufgaben sind nicht klein genug.

+0

ich bin mir nicht sicher, aber gut zu wissen, wie auch immer, ich habe javaFX's Timeline stattdessen verwendet, die (zumindest für mich) ist besser –

2

Dies liegt daran, dass Sie den Timer manuell entsorgen müssen. Wenn Sie java.util.Timer verwenden, müssen Sie cancel Methode aufrufen, um Ressourcen freizugeben.

+0

können Sie sagen, wie? –

+0

name_of_timer.cancel(); ? –

+0

Ja. In diesem Fall 'messagePrinter.cancel();' – talex

1

Ihr Timer wird mit einem Nicht-Daemon-Thread erstellt, Nicht-Daemon-Threads können die Beendigung Ihres Programms blockieren. Sie sollten den Konstruktor für den Timer verwenden, der einen Daemon-Thread verwendet.

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

Aber ich würde eine ExecutorService wie Andrew Lygin schlägt werden.

Verwandte Themen