How pause and then resume a thread?
Using wait()
and notify()
methods:
wait()
- Causes the current thread to wait until another thread invokes the
notify()
method or thenotifyAll()
method for this object.
notify()
- Wakes up a single thread that is waiting on this object's monitor.
How to Pause and Resume a Thread in Java from another Thread
You can't definitively pause one thread from another in the way you seem to want.
What you need to do instead, is signal that the other thread should stop, by setting some sort of flag. The thread in question must have logic to check this flag and pause its work when that happens.
So in this particular case, perhaps change MyThread
as follows:
class MyThread extends Thread {
private volatile boolean running = true; // Run unless told to pause
...
@Override
public void run()
{
for(int i=0 ; ; i++)
{
// Only keep painting while "running" is true
// This is a crude implementation of pausing the thread
while (!running)
yield;
area.setText(i+"");
}
public void pauseThread() throws InterruptedException
{
running = false;
}
public void resumeThread()
{
running = true;
}
}
This is a crude example that for brevity uses a sort of spinlock rather than proper monitor-based sleeping. Hopefully though it communicates the idea of how you use a flag to control the pausing of the thread.
Note that if you were doing some long-running set of steps within the block, instead of just the setText
call, it would be good practice to check Thread.currentThread().interrupted()
between each of the steps - and exit the loop if the itnerrupt flag is set. This is broadly what the built-in blocking methods (e.g. I/O) do so that they can be interrupted by other threads - since the running
flag is only checked one per loop, it doesn't do much good to set it if each loop takes 20 minutes.
Pause Thread and resume it from where it stopped
There are plenty of ways to manipulate threads.
suspend()
: puts a thread in a suspended state and can be resumed using resume()
stop()
: stops a thread
resume()
: resumes a thread, which was suspended using suspend()
.
notify()
: Wakes up a single thread.
wait()
: makes the current thread wait.. (or sleep) until another thread invokes the notify()
method for that thread.
notifyAll()
: will wake up all sleeping (waiting) threads.
Note
In the latest versions of Java resume( ), suspend( ) and stop( ) has been deprecated
Question from OP
but when I wake it up, it resumes from where? Does it start from the beginning or from where it left?
Imagine a simple for
-loop.
Starting thread 1.
Starting thread 2.
Thread 1: 0
Thread 2: 0
Thread 1: 1
Thread 2: 1
Pausing thread 1.
Thread 2: 2
Thread 2: 3
Thread 2: 4
Resuming thread 1.
Thread 1: 2
Thread 2: 5
How do I pause Threads properly with wait() and notify()
So given this is your Thread class:
public class MyThread extends Thread
{
First, you need an lock object. This object can be everything, and if you use an existing object this takes less memory. Also define a flag if the bot should be paused.
public Object lock = this;
public boolean pause = false;
Now, define a pause()
and continue()
method for the thread. This sets the pause
flag.
public void pause ()
{
pause = true;
}
public void continue ()
{
pause = false;
Here you need to wake up the thread. Note the synchronized on the lock object so that you don't get an IllegalMonitorStateException
.
synchronized (lock)
{
lock.notifyAll();
}
}
No, define a method that automatically pauses the thread when it should be paused. You might call this at every moment when the thread can be paused.
private void pauseThread ()
{
synchronized (lock)
{
if (pause)
lock.wait(); // Note that this can cause an InterruptedException
}
}
Now, you can define your thread in the run()
method:
public void run ()
{
task1();
task2();
pauseThread();
task3();
task4();
task5();
task6();
task7();
pauseThread();
task8();
task9();
task10();
}
}
Pause/Resume a Thread
You need to change your download()
method to check for a stop or pause event and then stop or pause the thread. It has to be this way as the JVM does not know what steps need to be done in order to safely pause/stop the thread.
You may end up using wait
but not the way you are using it. wait
causes the currently running thread to wait until some calls notify
on the object you have called wait
on.
In the download method you have a loop (read a block, write a block). You should add two checks in the loop.
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
if(paused) {
// How do you want to handle pausing? See below for options.
}
if(stopped) {
// delete the file and close the streams.
}
}
How you handle pausing is up to you. I can see two options: Save what you have as ".incomplete" and later restart the download using the Range header or continue looping with a pause (Thread.sleep, Object.wait or whatever).
I would go with the first option (Range Header). It is more work but also more robust.
how to pause a thread and resume it exactly where it was left off
There are two very useful classes in concurrency package - CountDownLatch
and CyclicBarrier
. If you need this behaviour only once, you probably want the first one (as it cannot be reset).
Thread 1 will await until notified by thread 2. Once it was counted down to 0, thread 1 will never block again at await()
:
CountDownLatch cdl = new CountDownLatch(1);
// thread 1:
cdl.await();
// thread 2:
cdl.countDown();
Threads will block at await()
until there are exactly two threads waiting:
CyclicBarrier barrier = new CyclicBarrier(2);
// both threads:
barrier.await();
EDIT:
Here is what I came up with when modifying your code, however it is unclear to me whether it is expected behaviour.
Note a volatile
keyword on the CountDownLatch
- it is very important here, otherwise taskThread
may cache the initial object (new CountDownLatch(0)
) and hence never block.
public class Test {
private Thread taskThread;
private Thread busyThread;
private volatile CountDownLatch cdl = new CountDownLatch(0);
public static void main(String args[]) throws Exception {
Test t = new Test();
t.runTaskThread();
t.runBusyThread();
}
public void runTaskThread() {
taskThread = new Thread(() -> {
for (int x = 0; x < 100; x++) {
waitIfSystemBusy();
System.out.println("I'm doing task A for process #" + x);
sleep(1000);
waitIfSystemBusy();
System.out.println("I'm doing task B for process #" + x);
sleep(200);
waitIfSystemBusy();
System.out.println("I'm doing task C for process #" + x);
sleep(300);
waitIfSystemBusy();
System.out.println("I'm doing task D for process #" + x);
sleep(800);
System.out.println("\n\n");
}
});
taskThread.start();
}
public void runBusyThread() {
busyThread = new Thread(() -> {
while (true) {
Random rand = new Random();
int randomNum = rand.nextInt(1000);
if (randomNum < 400) {
System.out.println("Wait...system is busy!!!");
cdl = new CountDownLatch(1); // signal taskThread to pause
sleep(3000);
cdl.countDown(); // signal taskThread to resume
} else {
sleep(300);
}
}
});
busyThread.start();
}
private void waitIfSystemBusy() {
try {
cdl.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Best Method to pause a Thread?
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.
Related Topics
How to Tell Jackson to Ignore a Property for Which I Don't Have Control Over the Source Code
Java Error: "Your Security Settings Have Blocked a Local Application from Running"
How to Wait Until an Element Is Present in Selenium
How to Save Preference User Settings in Java
How to Configure JPA for Testing in Maven
Convert Seconds Value to Hours Minutes Seconds
Access Restriction: Is Not Accessible Due to Restriction on Required Library ..\Jre\Lib\Rt.Jar
How to Draw in JPAnel? (Swing/Graphics Java)
Java.Lang.Noclassdeffounderror: Org/Hamcrest/Selfdescribing
What Is the Default Stack Size, Can It Grow, How Does It Work with Garbage Collection
Increasing Heap Space in Eclipse: (Java.Lang.Outofmemoryerror)
Singleton Design Pattern: Pitfalls
Lambdaconversionexception with Generics: Jvm Bug
Exclude @Component from @Componentscan