Reputation: 1193
I have a Runnable class which performs an operation continuously in its run method using an infinite while loop. Sometimes a user might want to pause/resume the operation. What is the best method to pause the Thread. I have two thoughts:
FIRST
class Foo extends Runnable {
@Override
public void run() {
while(true) {
if(pauseFlag)
try{
Thread.sleep();
} catch(InterrruptedException ie) {//...}
}
}
SECOND
class Foo extends Runnable {
@Override
public void run() {
while(true) {
//pause if user wants to pause
while(pauseFlag);
}
}
}
Because it has nothing to do with synchronization, i do not want to use wait/notify.
Upvotes: 1
Views: 7642
Reputation: 116908
In the FIRST case, when i use Thread.sleep inside loop the Netbeans IDE issues warning not to use Thread.sleep inside loop. Why is that?
I guess because Netbeans thinks that it won't be testing the loop condition and the code will pause unnecessarily.
In the SECOND case, when i use infinite empty while loop, is that a performance overhead?
Uh yes. Spinning a thread will take a CPU and be a performance sink.
Which method(mentioned above or otherwise) should i prefer to pause the action being performed by the Thread according to the users choice?
Neither? I would use a volatile boolean pauseFlag
for testing if the thread should pause, combined with wait/notify to unpause it. Or you can use an AtomicBoolean
which wraps a volatile boolean
but is also an object we can synchronize on. Maybe something like:
// using `AtomicBoolean` which wraps a `volatile boolean` but is const object
// NOTE: we _can't_ synchronized on Boolean, needs to be constant object reference
private final AtomicBoolean pauseFlag = new AtomicBoolean(false);
...
while (!Thread.currentThread().isInterrupted()) {
if (pauseFlag.get()) {
synchronized (pauseFlag) {
// we are in a while loop here to protect against spurious interrupts
while (pauseFlag.get())) {
try {
pauseFlag.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// we should probably quit if we are interrupted?
return;
}
}
}
}
...
}
...
public void pause() {
pauseFlag.set(true);
}
...
public void resume() {
pauseFlag.set(false);
synchronized (pauseFlag) {
pauseFlag.notify();
}
}
I guess if I were forced to pick from one of the two, I would pick the sleep(...)
loop. Even sleep(1)
is significantly better than a spin. Do you really need to un-pause quicker than ~1ms? But the wait/notify is the most efficient.
Because it has nothing to do with synchronization, i do not want to use wait/notify.
As mentioned by @Jon, some sort of synchronization is necessary here since you are trying to communicate between two threads. Certainly you need to have memory synchronization otherwise any updates to pauseFlag
will not be guaranteed to be shared between threads. This is handled by the volatile
primitive on pauseFlag
. By using wait/notify (which needs synchronized
) your code can be much more efficient about the wakeup.
Upvotes: 4
Reputation: 1502766
Because it has nothing to do with synchronization, i do not want to use wait/notify.
It has everything to do with synchronization. Presumably your user interaction occurs on a different thread - so you're trying to synchronize signals between the two threads.
You shouldn't use Thread.sleep
or a tight loop here. Either wait
/notify
or something similar using a higher-level construct in java.util.concurrent
is the right approach here.
Note that without any memory barriers, changes to your pauseFlag
from one thread may not be noticed in a different thread, so you'd at least want to make it volatile.
Upvotes: 3
Reputation: 533740
You are synchronizing a state change between threads so I would use wait(), however the alternative is to use a sleep. You could busy wait, but you wouldn't gain much but you would lose a CPU.
Upvotes: 1