Reputation: 1655
System.out.println("Thread state: " + threads[i].getState());
threads[i].notify();
Produces the following output:
Thread state: WAITING
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at MyPakc.An.run(An.java:49)
at java.lang.Thread.run(Thread.java:679)
What is going on? Why can I not notify a sleeping thread?
EDIT: The code for the threads[] class:
package Part2;
import java.util.List;
import javax.swing.JPanel;
class BThread extends Thread{
private boolean completedThisIter = false;
@Override
public synchronized void run() {
while (true) {
completedThisIter = false;
doStuff()
System.out.println("Completed iter");
completedThisIter = true;
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public boolean getCompletedThisIter() {
return completedThisIter;
}
}
EDIT: Here is the code that calls this
public synchronized void run(){
// OTHER STUFF
for (int iter = 0; iter < 1212; ++iter){
System.out.println("Iter " + iter);
lastAssignedBallIndex = -1;
for (int i = 0; i < numThreads; i++) {
//System.out.println("Num " + numThreads + " " + i);
//ballThreads[i] = new BallThread(ballList.subList(lastAssignedBallIndex+1,lastAssignedBallIndex+numBallsPerThread),
// ballPanel);
//lastAssignedBallIndex += numBallsPerThread;
System.out.println("State " + ballThreads[i].getState());
if (ballThreads[i].getState() == Thread.State.NEW) {
ballThreads[i].start();
} else { //if (ballThreads[i].getState() == Thread.State.BLOCKED) {
System.out.println("Thread state: " + ballThreads[i].getState());
ballThreads[i].notify();
}
}
//try{
for (int i = 0; i < numThreads; i++) {
while (!ballThreads[i].getCompletedThisIter()) {
System.out.println("iter:" + iter + " ball:" + i + " " + ballThreads[i].getCompletedThisIter());
//wait(); // TODO elliminate polling here
}
}
System.out.println("Joined");
//}
// catch(InterruptedException ie){ie.printStackTrace();}
ballPanel.repaint();
notifyAll();
try{
Thread.sleep(2);
}
catch (InterruptedException ie){}
}
}
Upvotes: 0
Views: 1225
Reputation: 182753
You are completely misunderstanding the way the wait
/notify
mechanism works. The thread has to decide that there is something it needs to wait for. Then the thread must call wait
. Then that something has to happen. Then you call notify
to tell the thread that something happened.
You cannot have the thread call wait
without first determining that there is something specific that it should wait for. And you cannot call notify
until something has already happened that the thread needs to be notified about. The something that has happened should be the same thing the thread was checking for when it decided to wait.
The reason you are getting in an error is the synchronization associated with the thing waited for simply doesn't exist which violates the semantics of wait
/notify
.
If you're waiting for a mailbox to be non-empty, then you should check if the mailbox is empty, and if so, call wait
. Make sure you are still inside the mailbox's synchronized routine, otherwise you can't know the mailbox is (still) empty. Then when you put a letter in the mailbox (which has to be inside the mailbox's synchronized routine), you call notify
to let any waiting threads know the mailbox has changed state. You have to be waiting for something the thread can test, such as the state of the mailbox.
Upvotes: 1
Reputation: 143866
You're printing out the state of a ballThreads[i]
then notifying a threads[i]
. Not sure if this is intended behavior but you're not allowed to notify a thread when you don't own the object's monitor. Are you sure you're calling this inside a synchronized()
block for the threads[i]
object?
EDIT:
Yes, the method that this code is taken out of is synchronized
After your edit to your question, the synchronized
is on the method, and not the monitor of the object, you need to put your code in a block that looks like this:
synchronized(threads[i]) {
// some stuff
threads[i].notify();
}
The important bit here (as opposed to the synchronized
keyword in a method declaration) is that you synchronize on an Object, then inside this block, you call notify()
on the Object. Examples:
public void run()
{
synchronized(myObject) {
// do some stuff
myObject.notify();
}
}
or
public void run()
{
synchronized(thread1) {
// do some stuff
thread1.notify();
}
}
or
public void run()
{
synchronized(syncObject) {
// do some stuff
syncObject.notify();
}
}
See the pattern? More info here: http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
Upvotes: 2
Reputation: 9914
wait()
and notifiy()
requires that you synchronize on the object that you are waiting on. if you do a wait()
and notify()
on the same object that you used to lock the sync block, then you will get rid of the illegal monitor state exception
Upvotes: 1