Search code examples
javamultithreadingtimertask

TimerTask doesn't stop immediately after timer.cancel() being called from another thread?


I have an applet to do following things: Main thread and thread t1 request something cyclically, a button will stop both.

public class HttpsConn {
    private static boolean stop = false;
    private static Timer t = null;

    public static void main(String[] arg)  {
        t = new Timer();
        A a = new A();
        t.schedule(a, 0, 1000);
        B b = new B();
        Thread t1 = new Thread(b);
        t1.start();
    }
    static class A extends TimerTask {
        @Override
        public void run() {
            if (stop)
                t.cancel();     //this.cancel();
            System.out.println("something to do");
        }
    }
    static class B extends A implements Runnable {
        @Override
        public void run() {
            System.out.println("simulate an operation from Swing Applet (click RESET button) to interrupt the thread.");
             stop = true;
        }
    }
}

I except the result:

something to do
simulate an operation from Swing Applet (click RESET button) to interrupt the thread.

What I get:

something to do
simulate an operation from Swing Applet (click RESET button) to interrupt the thread.
something to do

I find a similar question here, the answer says call cancel from within the run(), but it seems not work here. Then how to avoid the unexpected running? And what's the difference between t.cancel() and this.cancel() on the line with comment? They lead to same result. Thanks!


Solution

  • Your A is scheduled to run with an initial delay of 0 and subsequent delays of 1 second.

    The first something to do is the first time it executes after a 0 delay. The stop flag has not been set so it just prints and exits.

    One second later it is invoked again by the Timer. It checks for the stop flag, cancels the timer (because B has executed and set it) and prints a second something to do. It should not run again as the timer task has now been cancelled.

    To avoid this seemingly strange behavior you could use something like:

            if (!stop) {
                System.out.println("something to do");
            } else {
                t.cancel();     //this.cancel();
            }
    

    Remember that cancel only cancels the Timer, it does not abort the execution of the Runnable.