为什么必须从同步方法或者块中调用wait(),notify()和notifyAll()方法

时间:2020-01-09 10:35:07  来源:igfitidea点击:

为什么必须从同步方法或者块中调用Java中的wait(),notify()和notifyAll()方法。这篇文章提供了一些要点,为什么在同步上下文中调用wait(),notify()和notifyAll()方法才有意义。

我们需要注意以下两点:

1 –正如我们必须知道的那样,Java中的每个对象都有一个与之关联的锁(也称为监视器)。当线程进入同步方法或者同步块时,它将获取该锁。尝试执行相同代码的所有其他线程(在同步方法或者同步块中)必须等待第一个线程完成并释放锁。

2 – wait(),notify()和notifyAll()方法的说明

  • wait –使拥有对象的监视器锁的当前线程放弃锁并进入等待状态。
  • notify –唤醒正在该对象的监视器上等待的单个线程。
  • notifyAll –唤醒该对象的监视器上正在等待的所有线程。

使用这两点,我们只需要连接点即可理解为什么必须从同步方法或者块中调用Java中的wait(),notify()和notifyAll()方法。

从等待描述中可以清楚地看到,notify和notifyAll方法只能在线程拥有对象锁时在对象上调用这些方法。现在,线程何时拥有对象的锁?获取它并进入同步块或者方法后。因此,很明显,当线程具有对象的锁时,可以在同步上下文中调用wait(),notify()和notifyAll()方法。

从同步方法或者块外部调用方法

如果我们在未同步的方法中调用wait,notify和notifyAll方法,则该程序将编译,但是在运行该程序时,我们会收到IllegalMonitorStateException。

例如,在下面的代码中,从同步块中调用wait()方法,将编译代码,但在运行时将抛出IllegalMonitorStateException。

public void increment(){
  synchronized(this){
    for(int i = 1; i <= 5 ; i++){
      System.out.println(Thread.currentThread().getName() + " i - " + i);
    }
  }
  try {
    // calling wait method outside synchronized context
    this.wait();
  } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
}

输出:

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Unknown Source)
	at com.theitroad.Counter.increment(SynchronizedDemo.java:10)
	at com.theitroad.SynchronizedDemo.run(SynchronizedDemo.java:31)