Reputation: 2861
In a first Java thread I have:
while (!isDone) {
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
doSomeVeryLongRunningTask();
}
In another thread, I want to send a notify signal:
synchronized (thr1) {
thr1.notify();
}
However, if the doSomeVeryLongRunningTask()
method is running, I don't want the second thread to get blocked. I only want to notify the first thread if it is waiting so that the second thread can continue it tasks without getting locked.
How might I fix the code above to accomplish this?
Upvotes: 1
Views: 2113
Reputation: 298153
They problem you want to fix does not exist. synchronized
blocks will block the thread only if another thread is already inside a synchronized
block synchronizing on the same object. Since your doSomeVeryLongRunningTask()
will be called outside the synchronized
block the notifying thread will never get blocked if the other thread is inside the doSomeVeryLongRunningTask()
method.
But this raises another problem. You seem to be thinking, that wait
and notify
invocations are always paired. This is not the case, you may call notify
as often as you wish without anyone listening to it. It might be also the case that a wait
invocation returns “spuriously”, i.e. for no apparent reason. You therefore need to define another “hard condition” which is defined by a state that is modified and checked inside the synchronized
block.
E.g. inside the class whose instance you have in your thr1
variable, you can define a boolean
flag:
boolean condition;
Then you modify you waiting method like this:
while(!isDone) {
try {
synchronized(this) {
while(!condition) wait();
if(isDone) break;// skip doSomeVeryLongRunningTask()
condition=false;
}
} catch(InterruptedException e) {
e.printStackTrace();
}
doSomeVeryLongRunningTask();
}
And the notifying code to:
synchronized(thr1) {
thr1.condition=true;
thr1.notify();
}
This way your notifying code still won’t get blocked (at least never for a significant time) but the waiting thread will wait for at least one notification to happen within one loop cycle.
Upvotes: 4
Reputation: 14269
The synchronized in modern Java is about as fast as --i
, because this is about what is internally happening thanks to hardware compareAndSet
mechanisms. The only moment this slows down noticeably, is when more than one thread is arriving at the synchronized block and therefore at least one has to wait.
Upvotes: 0
Reputation: 23015
It seems what is blocking your program is not the notify()
(it doesn't block ever) but the two synchronized
blocks that are synchronizing on the same object.
I don't think there is a workaround to what you ask. Check this link to know why: http://javarevisited.blogspot.com/2011/05/wait-notify-and-notifyall-in-java.html
Upvotes: 1
Reputation: 21
The advised pattern is to use notifyAll() AND to have ALL waiting threads check their wake-up condition each time they are notified AND before starting the first Wait.
Upvotes: 0
Reputation: 73558
The notify()
call doesn't block. Only wait()
blocks. You can call notify even if there isn't another thread waiting, but then make sure your algorithm is correct. If you expect to notify only once, then another thread arriving after the notify will wait() forever.
Upvotes: 0