为什么必须在synchronized方法/代码块中调用wait,notify和notifyAll

时间:2018-09-18 04:21:02  来源:快乐IT  作者:学无止境

 为什么必须在synchronized方法/代码块中调用wait(),notify()和notifyAll()?这是一个非常常见的Java多线程问题。它与另一个多线程问题密切相关: 为什么wait(),notify()和notifyAll()方法都定义在Object类中?

 
在讨论这个问题之前,我们应该注意几点:
 
1. Java中创建的每个对象都有一个关联的监视器Monitor(也就是互斥锁)。在任何给定时间,只有一个线程可以拥有该监视器。
2. 在Java中使用此监视器来实现同步。当任何线程进入同步方法/块时,它要获取指定对象的锁。当任何线程获得锁时,也就是说它已获取了该监视器。所有其他需要执行相同同步代码(锁定监视器)的线程将被挂起,直到最初获取锁的线程释放它为止。
3. wait方法告诉当前线程(在同步方法或块内执行代码的线程)放弃监视器并进入等待状态(waiting state)。
4. notify方法唤醒正在此对象监视器上等待的单个线程。
5. notifyAll方法唤醒在同一对象上调用wait()的所有线程。
 
任何方法或代码块,如果没有使用关键字synchronized限定,可以在任何时间由多个线程执行,因为对象的监视器(锁)没有被使用。在同步方法(或存在同步块)的情况下,只有获取对象监视器的单个线程才能访问该代码。
 
现在已经清楚了。因为wait()方法是说线程释放对象的锁并进入休眠状态,而notify / notifyAll方法是说要通知等待对象锁的那些线程。因此,只有当前线程已经获取对象的锁时,才能在该对象上调用wait(),notify()和notifyAll()方法。
事实上,不这样做会导致java.lang.IllegalMonitorStateException。
 
举个例子,假设我有如下代码,我注释掉了synchronized关键字并尝试调用wait:
 
while(true){
    //synchronized (sharedListObj) {
    // While condition as mandated to avoid spurious wakeup
    while(sharedListObj.size() >= 1){
        try {
            sharedListObj.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    // Putting value in the list
    System.out.println("Adding to queue - " + Thread.currentThread().getName() + " " + ++i);
    sharedListObj.add(i);
    //sharedListObj.notify();    
    // To get out of while(true) loop
    if(i > 4) break;
    //}
}
 
 
运行代码会抛出异常:
Exception in thread "Producer" java.lang.IllegalMonitorStateException
 at java.lang.Object.wait(Native Method)
 at java.lang.Object.wait(Object.java:502)
 at org.netjs.examples.Producer.run(InterThreadDemo.java:20)
 at java.lang.Thread.run(Thread.java:745)
 
总结一下。wait()方法告诉当前线程(在同步方法或块中执行代码的线程)放弃监视器。仅当线程在同步上下文中执行时,才由该线程获取对象的锁。获取了锁之后才能使用wait()方法,wait()要求线程在这个同步方法/块中释放锁。
 
同样:当调用object的notify()或notifyAll()方法时,单个线程(对于notify)或所有线程(对于notifyAll)等待对象锁的状态改变为runnable并尝试获取该对象锁,然后获取锁的线程开始执行。
notify()和notifyAll()方法可以通知其他线程,对象的锁可以被获取了,只有从同步对象调用这些方法时。
 
 
英文原文地址:https://netjs.blogspot.com/2015/07/why-wait-notify-and-notifyall-called-from-synchronized-java.html
 

相关文章

文章评论

共有  0  位网友发表了评论 此处只显示部分留言 点击查看完整评论页面