Java - Timer is not being removed after execution

Abdullah Asendar :

I have an application that starts a timer to splash a message on user actions. In JDK profiler it seems that all other threads are being removed after execution by GC (I guess) but the timers a created is not being removed. What could be happening there?

my 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

Is it because I am using a static method or should I destroy it myself?

Andrew Lygin :

Actually, you have no problem with timer termination here. The threads you see in the profiler are already terminated – they have a white box on the left side which indicates that they are dead.

The profiler shows all the threads that were created during the program execution, even if those threads are already dead and garbage-collected.

You can easily confirm that by doing the following: Instead of a lambda, create a subclass of TimerTask that will do the same and redefine its finalize() method to print something. You'll see that when garbage collections are performed, your tasks are finalized. It only can happen if threads are stopped, because it's the only place in the Thread class where it drops the reference to its Runnable (which TimerTask implements).

Another way to confirm that is just to select 'Live Threads' from the View dropdown list on top of the table.

In addition, I would recommend you to substitute Timer for something better. It's too wasteful to create a thread every time you need to delay some task. Have a look at ScheduledThreadPoolExecutor, it seems much more appropriate for your task:

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

You can add more than one thread to the executor if you have too many scheduled tasks at once and those tasks are not small enough.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=456621&siteId=1