Using wait() might not work as you expect. The wait/notify is built as a simple implementation of the sempaphore (as an object instance wide monitor) context of concurrent programming.
Calling notify() from any other thread not locking the monitor of the thread object instance won't work, see Java Wait and Notify: IllegalMonitorStateException
You can easily achieve your goal by checking the suspended flag regularly, and just wait a bit if your thread shall not do anything:
public class SuspendDemo implements Runnable {
public Thread t;
private final String threadName;
boolean suspended = false;
SuspendDemo(final String name){
threadName = name;
System.out.println("Creating " + threadName );
}
@Override
public void run() {
System.out.println("Running " + threadName );
try {
while (true) {
System.out.println("Thread: " + threadName);
// Let the thread sleep for a while.
Thread.sleep(300);
while(suspended) {
System.out.println("suspended");
Thread.sleep(50);
}
}
} catch (final InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
void suspend() {
suspended = true;
}
void resume() {
suspended = false;
notify();
}
public static void main(final String[] args) throws InterruptedException {
final SuspendDemo R1 = new SuspendDemo( "Thread-1");
R1.start();
R1.suspend();
Thread.sleep(500);
R1.resume();
}
}
Resulting:
> Creating Thread-1
> Starting Thread-1
> Running Thread-1
> Thread: Thread-1
> suspended
> suspended
> suspended
> suspended
> Thread: Thread-1
> Thread: Thread-1
> Thread: Thread-1
The suspend flag is a native boolean, so writing it is an atomic operation, therefore you can go without synchronization on anything.
I suggest to fully understand concurrent programming and the monitor concurrency model what Java uses, before using synchronized. I found using synchronize(this) blocks hard to maintain and prone to mistakes.
The next example solves the problem with wait() and notifyAll(). Note the use of synchronized methods for locking the monitor of the thread object instead of the synchronize(this) blocks.
public class SuspendDemo implements Runnable {
public Thread t;
private final String threadName;
boolean suspended = false;
SuspendDemo(final String name){
threadName = name;
System.out.println("Creating " + threadName );
}
@Override
public void run() {
System.out.println("Running " + threadName );
try {
while (true) {
System.out.println("Thread: " + threadName);
// Let the thread sleep for a while.
Thread.sleep(300);
work();
}
} catch (final InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
synchronized protected void work() throws InterruptedException {
while(suspended) {
System.out.println("suspended");
wait();
System.out.println("resumed");
}
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
synchronized void suspend() {
suspended = true;
notifyAll();
}
synchronized void resume() {
suspended = false;
notifyAll();
}
public static void main(final String[] args) throws InterruptedException {
final SuspendDemo R1 = new SuspendDemo( "Thread-1");
R1.start();
R1.suspend();
Thread.sleep(500);
R1.resume();
}
}