I'm trying to use class as Observer and Observable. This class will be runned as thread. In run() method thread will be waiting and after getting event thread will be notifyed. There is example code:
public class Runner {
public static void main(String[] args) {
MyThread mt = new MyThread();
Controller c = new Controller();
mt.addObserver(c);
c.addObserver(mt);
Thread t = new Thread(mt);
t.start();
}
}
public class MyThread extends Observable implements Observer, Runnable {
static private Integer op = 0;
public void run() {
synchronized (this) {
while (true) {
op++;
System.out.println(op + " Thread started");
super.setChanged();
super.notifyObservers(new Object());
op++;
System.out.println(op + " Thread send event");
try {
op++;
System.out.println(op + " Thread wait");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@Override
public void update(Observable arg0, Object arg1) {
op++;
System.out.println(op + " Thread got event");
synchronized (this) {
op++;
System.out.println(op + " We are in synchronized block!");
this.notify();
}
}
}
public class Controller extends Observable implements Observer {
public void update(Observable arg0, Object arg1) {
System.out.println("Controller get and send event");
super.setChanged();
super.notifyObservers(new Object());
}
}
Getted output is:
1 Thread started
Controller get and send event
2 Thread got event
3 We are in synchronized block!
4 Thread send event
5 Thread wait
And thread stay locked. Expected output:
1 Thread started
Controller get and send event
2 Thread got event
3 Thread send event
4 Thread wait
5 We are in synchronized block!
What's going wrong? Why I come into synchronized block before monitor released? P.S. I have an idea that problem is adding observer to MyThread object, may be i will add observer to Thread object? But how I could do this?
Well, I think the main thing you are stumbling upon is that the synchronized
keyword resembles a reentrant lock (http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html).
That means, while you are in your MyThread
's run
method you are notifying the Controller
. This one then calls the update
of your MyThread
which enters the synchronized
block (since it is reentrant) and completes this method. Afterwards, the Controller.update
method returns and the rest of your MyThread.run
method continues, thus being stuck on this.wait()
.