I have a long-running Runnable. It performs a large number of iterations inside a while-loop in its run() function. I need functionality to pause and resume the runnable, which I implemented using a volatile Boolean pauseFlag
that can be set by another thread.
Once the Runnable has detected that pauseFlag
is true
, it calls pauseFlag.wait()
to pause its execution. Resuming is done through setting pauseFlag
to false
and then calling pauseFlag.notifyAll()
.
So the pauseFlag
both acts as a flag and a mutex. This combined functionality does not work, however. The Runnable keeps blocking on pauseFlag.wait()
indefinitely.
If I create a separate mutex, say, Object mutex = new Object();
and use mutex.notifyAll()
/ mutex.wait()
, while still using pauseFlag
as a boolean flag, the Runnable does behave as intended.
The non-working code is shown below:
public class PausableRunnable implements Runnable
{
private boolean done;
private volatile Boolean pauseFlag = false;
/** Pause execution. This is an asynchronous (non-blocking) call. */
public void pause() // <-- called by another thread
{
pauseFlag = true;
}
/** Resume execution */
public void resume() // <-- called by another thread
{
pauseFlag = false;
synchronized (pauseFlag)
{
pauseFlag.notifyAll();
}
}
@Override
public void run()
{
try
{
while (!done && !Thread.currentThread().isInterrupted())
{
while (pauseFlag)
{
synchronized (pauseFlag)
{
// Pause flag was set. Suspend until we are notified that we can continue
pauseFlag.wait();
}
}
// execute our main behaviour. set done = true when done iterating.
// ....
}
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
So, while I have found a solution by using a separate object, I'd like to understand the issue. Why doesn't the above implementation work?
I made this very same mistake once.
wait
/notify
works on an object, not a reference
When you change the object referred to by
private volatile Boolean pauseFlag
the wait
is still referring to the original object. (As pointed out in the comments, there will usually be only two Boolean objects, TRUE
and FALSE
, making this even harder to debug, because you might get the correct one by chance)
So it's best to use a final
reference that never changes its underlying object when using wait/notify.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With