Reputation: 117
In the following code the notifyAll() is called but does not reactivate the other threads. The output I get is
beta waiting to get notified at time: 1441870698303, activeWriters: 1
alpha waiting to get notified at time: 1441870698303, activeWriters: 1
delta notify all at time: 1441870698403, activeWriters: 0
public class Waiter implements Runnable{
private static int activeWriters;
public Waiter(Message msg){
}
@Override
public void run() {
beforeWrite();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
afterWrite();
}
protected synchronized void beforeWrite(){
while (activeWriters > 0 ) {
try {
System.out.println(Thread.currentThread().getName() +" waiting to get notified at time: "+System.currentTimeMillis()+ ", activeWriters: " + activeWriters);
wait();
System.out.println(Thread.currentThread().getName() +" waiting got notified at time: "+System.currentTimeMillis()+ ", activeWriters: " + activeWriters);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
++activeWriters;
}
protected synchronized void afterWrite(){
--activeWriters;
System.out.println(Thread.currentThread().getName() +" notify all at time: "+System.currentTimeMillis() + ", activeWriters: " + activeWriters);
notifyAll();
}
}
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter1 = new Waiter(msg);
Waiter waiter2 = new Waiter(msg);
Waiter waiter3 = new Waiter(msg);
new Thread(waiter1,"alpha").start();
new Thread(waiter2, "beta").start();
new Thread(waiter3, "delta").start();
}
}
Upvotes: 2
Views: 1008
Reputation: 1526
The calls wait()
and notify*()
work on a specified object, meaning that notify*()
wakes up threads which called wait()
on the same object.
In your case you call wait()
and notifyAll()
on 3 different objects which aren't connected, so this can't work.
You can add a static mutex:
private static final Object mutex = new Object();
and then call wait()
and notify*()
on this object. Remeber to synchronize on the mutex first:
synchronized (mutex) {
...
mutex.wait();
...
}
and:
synchronized (mutex) {
...
mutex.notifyAll();
...
}
All access to activeWriters
must be in these synchronized
blocks for 2 reasons. Currently access to it is effectively unsynchronized, because you synchronize on 3 different objects. Apart from that activeWriters
is your condition variable, and you want to notify*()
other threads that it changed. For this to work the change of the variable and the notify*()
call must be in the same synchronized
block.
Upvotes: 4
Reputation: 7804
There is a major design flaw in your program.
You are creating 3 separate instances of Waiter class and expect all them to access activeWriters
in synchronized fashion. This is not possible because instance methods will acquire different locks but modify same static variable activeWriters
.
To provide static variables concurrent access, you should access them via. synchronized static methods.
One way could be to make beforeWrite()
and afterWrite()
methods static
.
Upvotes: 0