我正在尝试使用class作为Observer和Observable。该类将作为线程运行。在run()方法中,线程将等待,并且在获取事件线程之后将被通知。有示例代码:
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输出是:
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
线程保持锁定状态。预期产出:
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!
出了什么问题?为什么我在监视器发布之前进入同步块? 附:我有一个想法,问题是将观察者添加到MyThread对象,可能是我会将观察者添加到Thread对象?但我怎么能做到这一点?
答案 0 :(得分:1)
嗯,我认为您遇到的主要问题是synchronized
关键字类似于可重入锁(http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html)。
这意味着,当您使用MyThread
的{{1}}方法时,您正在通知run
。然后,这会调用Controller
的{{1}} update
进入MyThread
块(因为它是可重入的)并完成此方法。之后,synchronized
方法会返回,并且Controller.update
方法的其余部分会继续,因此会停留在MyThread.run
上。
答案 1 :(得分:1)
设置断点并单步执行/调试应用程序将帮助您找到导致此行为的原因。
原因是在线程开始等待之前调用MyThread.update
,并且没有其他线程可以唤醒此线程。你需要第二个线程。
在MyThread.run
方法中,您使用此行通知Controller
对象:
super.notifyObservers(new Object());
这会调用update
对象的Controller
方法,然后调用update
对象的MyThread
方法(通过通知)打印同步阻止消息。
然后,您notifyObservers
中的MyThread.run
来电回复,然后才能接到wait
方法的来电。
要达到预期的结果,您需要第二个线程在您等待后通知您的MyThread
对象。
使用主线程的最简单示例需要进行以下更改:
删除Controller.update
中的通知:
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());
}
}
在启动MyThread
后添加通知,而不是从主线程调用。
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();
//add the following:
try {
Thread.sleep(1000); //sleep for a while to make sure MyThread is waiting
} catch (InterruptedException ex) {
Logger.getLogger(Runner.class.getName()).log(Level.SEVERE, null, ex);
}
c.notifyObservers(); //notify MyThread
}
这将产生以下结果:
1 Thread started
Controller get and send event
2 Thread send event
3 Thread wait
4 Thread got event
5 We are in synchronized block!
6 Thread started
Controller get and send event
7 Thread send event
8 Thread wait
如您所见,MyThread.run
在收到通知后继续