简体   繁体   中英

Safely pausing and resuming a thread

I want to create a thread to make some HTTP requests every few seconds and is easy to pause and resume at a moments notice.

Is the way below preferred, safe and efficient?

public class Facebook extends Thread {

    public boolean running = false;

    public void startThread() {
        running = true;
    }

    public void stopThread() {
        running = false;
    }

    public void run() {
        while(true) {
            while(running) {
                //HTTP Calls
                Facebook.sleep(2000);
            }
        }
    }

}

Your Code:

In your example, the boolean should be volatile boolean to operate properly. The other issue is if running == false your thread just burns CPU in a tight loop, and you probably would want to use object monitors or a Condition to actually wait idly for the flag to become true again.

Timer Option:

I would suggest simply creating a Timer for this. Each Timer implicitly gets its own thread, which is what you are trying to accomplish.

Then create a TimerTask ( FacebookTask below is this) that performs your task and from your main control class, no explicit threads necessary, something like:

Timer t;

void resumeRequests () {
    if (t == null) { // otherwise its already running
        t = new Timer();
        t.scheduleAtFixedRate(new FacebookTask(), 0, 2000);
    }
}

void pauseRequests () {
    if (t != null) { // otherwise its not running
        t.cancel();
        t = null;
    }
}

Note that above, resumeRequests() will cause a request to happen immediately upon resume (as specified by the 0 delay parameter); you could theoretically increase the request rate if you paused and resumed repeatedly in less than 2000ms. This doesn't seem like it will be an issue to you; but an alternative implementation is to keep the timer running constantly, and have a volatile bool flag in the FacebookTask that you can set to enable/disable it (so if it's eg false it doesn't make the request, but continues checking every 2000ms). Pick whichever makes the most sense for you.

Other Options:

You could also use a scheduled executor service as fge mentions in comments. It has more features than a timer and is equally easy to use; they'll also scale well if you need to add more tasks in the future.

In any case there's no real reason to bother with Thread s directly here; there are plenty of great tools in the JDK for this job.

The suggestion to using a Timer would work better. If you want to do the threading manually, though, then something more like this would be safer and better:

class Facebook implements Runnable {

    private final Object monitor = new Object();

    public boolean running = false;

    public void startThread() {
        synchronized (monitor) {
            running = true;
            monitor.notifyAll();
        }
    }

    public void stopThread() {
        synchronized (monitor) {
            running = false;
        }
    }

    @Override
    public void run() {
        while(true) {
            try {
                synchronized (monitor) {
                    // Wait until somebody calls startThread()
                    while (!running) {
                        monitor.wait();
                    }
                }

                //HTTP Calls
                Thread.sleep(2000);
            } catch (InterruptedException ie) {
                break;
            }
        }
    }
}

Note in particular:

  1. You should generally implement Runnable instead of subclassing Thread , then use that Runnable to specify the work for a generic Thread . The work a thread performs is not the same thing as the thread itself, so this yields a better model. It's also more flexible if you want to be able to perform the same work by other means (eg a Timer ).
  2. You need to use some form of synchronization whenever you want two threads to exchange data (such as the state of the running instance variable). There are classes, AtomicBoolean for example, that have such synchronization built in, but sometimes there are advantages to synchronizing manually.
  3. In the particular case that you want one thread to stop work until another thread instructs it to continue, you generally want to use Object.wait() and a corresponding Object.notify() or Object.notifyAll() , as demonstrated above. The waiting thread consumes zero CPU until it is signaled. Since you need to use manual synchronization with wait/notify anyway, there would be no additional advantage to be gained by using an AtomicBoolean .

Edited to add:

Since apparently there is some confusion about how to use this (or the original version, I guess), here's an example:

class MyClass {
    static void main(String[] args) {
        FaceBook fb = new FaceBook();
        Thread fbThread = new Thread(fb);

        fbThread.start();

        /* ... do stuff ... */

        // Pause the FaceBook thread:
        fb.stopThread();

        /* ... do more stuff ... */

        // Resume the FaceBook thread:
        fb.startThread();

        // etc.

        // When done:
        fbThread.interrupt(); // else the program never exits
    }
}

我建议您使用受保护的块并将线程附加到计时器

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