简体   繁体   中英

Best Method to pause a Thread?

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);
        }
    }
}
  • 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?
  • In the SECOND case, when i use infinite empty while loop, is that a performance overhead?
  • Which method(mentioned above or otherwise) should i prefer to pause the action being performed by the Thread according to the users choice?

Because it has nothing to do with synchronization, i do not want to use wait/notify.

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM