您误解了
wait()工作原理。调用
wait一个对
Thread对象不会暂停该线程;
相反,它告诉当前正在运行的线程等待其他事件发生。为了解释原因,我需要备份一点并解释
synchronized实际的作用。
输入
synchronized块时,将获得与对象关联的 监视器 。例如,
synchronized(foo) {获取与对象关联的监视器
foo。
一旦有了监视器,在退出同步块之前,没有其他线程可以获取它。这是
wait和
notify进来。
wait是Object类上的一种方法,该方法告诉当前正在运行的线程临时释放其持有的监视器。这允许其他线程在上同步
foo。
foo.wait();
该线程将不会继续,直到其他人调用
notify或
notifyAll打开
foo(或线程被中断)。一旦发生这种情况,该线程将尝试重新获取监视器
foo,然后继续。请注意,如果有任何其他线程在等待获取监视器,那么它们可能会首先进入-
无法保证JVM将分发锁的顺序。请注意,
wait()如果没有人致电
notify或,它将永远等待
notifyAll。通常最好使用
wait超时的其他形式。当有人呼叫
notify/
notifyAll或超时到期时,该版本将被唤醒。
因此,您需要一个线程来进行等待,而另一个线程来进行通知。双方
wait并
notify必须持有他们试图等待或通知的对象监视器;
这就是为什么您看到IllegalMonitorStateException的原因。
一个示例可以帮助您理解:
class RepaintScheduler implements Runnable { private boolean paused = false; private final Object LOCK = new Object(); public void run() { while (true) { synchronized(LOCK) { if (paused) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { repaint(); } } try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } } public void pause() { synchronized(LOCK) { paused = true; LOCK.notifyAll(); } } public void resume() { synchronized(LOCK) { paused = false; LOCK.notifyAll(); } }}然后,您的Applet代码可以执行以下操作:
public void init() { RepaintScheduler scheduler = new RepaintScheduler(); // Add listeners that call scheduler.pause and scheduler.resume btn_increment.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) { scheduler.resume(); }}); btn_decrement.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) { scheduler.pause(); }}); // Now start everything up Thread t = new Thread(scheduler); t.start();}请注意,Applet类不关心调度程序如何暂停/继续并且没有任何同步块。
因此,这里可能的事件顺序是:
- 线程A开始运行重绘计划程序。
- 线程A进入睡眠状态20毫秒。
- 线程B(事件分发线程)收到按钮单击;称为“暂停”。
- 线程B在LOCK上获取监视器。
- 线程B更新’paused’变量并调用LOCK.notifyAll。
- 没有线程在等待LOCK,因此没有发生任何有趣的事情。
- 线程B在LOCK上释放监视器。
- 线程A唤醒,再次经历其循环。
- 线程A在LOCK上获取监视器。
- 线程A认为应该暂停它,因此它调用LOCK.wait。
- 此时,线程A挂起,等待有人调用notifyAll。线程A在LOCK上释放监视器。
- 一段时间后,用户单击“恢复”。
- 线程B调用scheduler.resume。
- 线程B在LOCK上获取监视器。
- 线程B更新’paused’变量并调用LOCK.notifyAll。
- 线程A看到“ notifyAll”并唤醒。它试图获取LOCK上的监视器,但是它由线程B保留,因此线程A阻塞了。
- 线程B在LOCK上释放监视器。
- 线程A获取监视器并继续。
这一切有意义吗?
不需要单独的LOCK变量;我这样做是为了突出您没有在
Thread实例上调用wait /
notify的事实。同样,RepaintScheduler中的逻辑也不理想,而仅仅是说明如何使用等待/通知。



