How To Stop Timer Thread to Change Variable Value

Viewed 178

I have a Timer class that continuously runs. When it reaches five seconds, I would like to change a boolean value that will be used by another class. However, since it has its own thread, the value of the variable is not changing and I am unable to retrieve the changed boolean value.

public class Time extends TimerTask {
Timer s = new Timer();
boolean bool;
int secondsPassed = 0;
Toolkit toolkit = Toolkit.getDefaultToolkit();

public Time() {
    bool = false;
}
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        secondsPassed++;
        if(secondsPassed == 5) {
            System.out.println("Seconds passed: " + secondsPassed);
            toolkit.beep();
            bool = true;
        }
    }
};

public void nextPanel() {
    toolkit = Toolkit.getDefaultToolkit();
    s.scheduleAtFixedRate(task, 1000, 1000);
}

public boolean throwbool() {
    return bool;
}

}

How would I stop the thread so that after five seconds "bool" would become true and I can return the new value in my other class? The other class is a GUI so the changed value as a check to when to switch to another panel.

2 Answers

If the variable bool is accessed by multiple threads, you have a data race. The modifications made to bool may not be visible to other threads unless explicit synchronization is used to control access to bool. You can declare bool as volatile to achieve this, and all changes to bool should be visible to other threads immediately.

The Answer by Serdar is correct. In addition, you could use an executor service instead of TimerTask.

Timer and TimerTask classes are generally supplanted by the executor service framework, as noted in the Javadoc.

For a timed task, use a ScheduledExecutorService.

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ;

Define a Runnable object having a run method. You can use either lambda syntax or conventional syntax.

Runnable r = () -> {   // lambda syntax
    … work to be done on background thread …
};

Schedule your task to run once after five seconds.

ses.schedule( r , 5 , TimeUnit.SECONDS ) ;

You said your task should set a boolean to be communicated across threads. You need to make access to that boolean thread-safe. My preferred way to do that is to use an AtomicBoolean object to wrap the boolean value in thread-safe accessor methods. No need for volatile Or synchronized.

AtomicBoolean flag = new AtomicBoolean() ;

Your task can set that boolean.

Runnable r = () -> {   // lambda syntax
    flag.set( true ) ;  // Automatically thread-safe because of `AtomicBoolean`. 
};

If you prefer to produce a value, capture the ScheduledFuture object returned by the .schedule method. That future object can be asked for the result of the task being performed on the background thread.

Be sure to eventually shut down the executor service. Otherwise the backing thread pool may run indefinitely like a zombie ‍♂️.

You said:

The other class is a GUI

What GUI toolkit? If Swing, JavaFX, or Vaadin, never access any widgets within the GUI from a background thread. Use whatever appropriate mechanism is provided by the GUI framework to request the GUI to run some code on its own thread to update its widgets.

Related