I’m trying to learn how to pause and resume a thread in java. I’m using an Applet that implements Runnablehas 2 buttons “Start” and “Stop”.
public void init(){
th = new Thread(this);
th.start();
btn_increment = new Button("Start");
btn_increment.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
th.notify();
}
});
add(btn_increment);
btn_decrement = new Button("Stop");
btn_decrement.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
try{
th.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});
add(btn_decrement);
}
The run method of the thread:
public void run(){
while(true){
repaint();
try{
Thread.sleep(20);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
Now whenever I try to to pause or resume the thread an exception is thrown:
Exception in thread "AWT-EventQueue-1" java.lang.IllegalMonitorStateException
Notes:
The previous code runs perfectly if I use the deprecated methods suspend() and resume(), but the documentation points out at using notify() and wait() instead with synchronization. I tried adding the word synchronized to the actionPerformed method, but it still throws the exception.
Can someone please explain WHY this isn’t working and how to solve the synchronization problem? Few explanation points would really be of much help 😉
You have misunderstood how
wait()works. Callingwaiton aThreadobject does not pause that thread; it instead tells the currently running thread to wait for something else to happen. To explain why, I’ll need to back up a bit and explain whatsynchronizedactually does.When you enter a
synchronizedblock you obtain the monitor associated with an object. For example,obtains the monitor associated with the object
foo.Once you have the monitor, no other threads can obtain it until you exit the synchronized block. This is where
waitandnotifycome in.waitis a method on the Object class that tells the currently running thread to temporarily release the monitor it holds. This allows other threads to synchronize onfoo.This thread will not resume until someone else calls
notifyornotifyAllonfoo(or the thread is interrupted). Once that happens, this thread will attempt to re-acquire the monitor forfooand then continue. Note that if any other threads are waiting to obtain the monitor then they might get in first – there is no guarantee of the order the JVM will hand out locks. Note thatwait()will wait forever if no-one callsnotifyornotifyAll. It’s usually best to use the other form ofwaitthat takes a timeout. That version will wake up when someone callsnotify/notifyAllor when the timeout has expired.So, you need one thread to do the waiting and a different thread to do the notifying. Both
waitandnotifymust hold the monitor on the object they are trying to wait on or notify; this is why you are seeing the IllegalMonitorStateException.An example might help you understand:
Your Applet code can then do this:
Note that the Applet class does not care about how the scheduler pauses/resumes and does not have any synchronized blocks.
So a possible sequence of events here is:
Does that all make sense?
Having a separate LOCK variable is not required; I’ve done that to highlight the fact that you are not calling wait/notify on a
Threadinstance. Similarly, the logic inside the RepaintScheduler is not ideal but is just there to illustrate how wait/notify could be used.