java中wait和notify的关系

java中,wait和notify这两个方法是一对,wait方法阻塞当前线程,而notify是唤醒被wait方法阻塞的线程。

首先,需要说明的是,wait和notify方法都是Object的实例方法,要执行这两个方法,有一个前提就是,当前线程必须获其对象的monitor(俗称“锁”),否则会抛出IllegalMonitorStateException异常,所以这两个方法必须在同步块代码里面调用,经典的生产者和消费者模型就是使用这两个方法实现的。

当前线程A获得对象obj的monitor,然后进入临界区(同步代码块),调用对象obj的wait方法,则线程A释放obj的monitor(执行了obj的wati方法之后,就会释放obj的monitor,不用等到执行完临界区,因为线程A会被阻塞在当前这个位置,同时cpu的相关寄存器会记住当前位置的堆栈信息),然后进入阻塞状态,同时线程A让出cpu,不再参与cpu的竞争,但是还会同时wait方法内部会不断地轮询线程A的InterruptStatus状态位(其实导致阻塞的方法一般都会做这个操作,就是不断地轮询中断状态位,以判断当前被阻塞的线程是否被提前取消了),以判断当前阻塞的状态是否会被中断(这里有点小矛盾,照理线程A不再参与cpu的竞争,又还不断轮询中断状态位,这个我还要研究下,有知道的可以留言评论指出,谢谢),等待其他线程调用A的notify(或notifyAll)来唤醒;然后线程B获取的obj的monitor之后,进去临界区,执行obj的notify方法,这时候,有点和wait方法不一样,就是调用了obj的notify之后,不会立刻释放obj的monitor同时唤醒线程A,而是要等到线程B执行完同步块代码,出了临界区,这时候才会释放obj的monitor,同时唤醒线程A,这时候线程A就会从新参与cpu的竞争,就有机会(因为可能其他线程也在竞争obj的monitor,如果之前有几个线程都在等待被obj的notify唤醒,则这时候就会有几个线程同时被唤醒,唤醒之后,因为obj的monitor同一时刻只允许一个线程拥有,所以被唤醒的几个线程究竟谁先获得obj的monitor继续往下面执行呢?这个就是根据操作系统的调度算法了。一个执行完同步块代码,释放obj的monitor之后,其他被唤醒的线程才会一个一个竞争获取obj的monitor,继续执行其wait方法后面的代码...)获取的obj的monitor,等到线程A重新获得obj的monitor之后,线程A会进入临界区,从wait方法后面继续执行(注意:这里进入临界区之后,不会从新从头执行临界区代码块,而会根据之前调用wait方法阻塞的时候,cpu记住的堆栈信息,会直接从wait方法后面的代码开始继续往下执行),直到出了临界区,释放obj的monitor。

这里还有一个要注意的问题就是,wait和notify调用的顺序一定要注意先后,如果先调用了obj的notify,然后才调用obj的wait方法的话,则调用了wait方法被阻塞的线程则不会被唤醒,会一直处于阻塞状态。

以下是我参考(http://www.cnblogs.com/hapjin/p/5492645.html)代码做的实践:

Service类

/**
 * Created by regis on 2017/4/23.
 */
public class Service {
    public void testMethod(Object lock) {
        try {
            synchronized (lock) {
                System.out.println("begin wait() ThreadName=" + Thread.currentThread().getName());
                lock.wait();
                if (Thread.currentThread().getName().equals("Thread-1")) {
                    Thread.sleep(50000);
                }
                System.out.println("end wait() ThreadName=" + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void synNotifyMethod(Object lock) {
        synchronized (lock) {
            System.out.println("begin notify() ThreadName=" + Thread.currentThread().getName());
            lock.notifyAll();
            System.out.println("end notify() ThreadName=" + Thread.currentThread().getName());
        }
    }
}

SynNotifyMethodThread类

/**
 * Created by regis on 2017/4/23.
 */
public class SynNotifyMethodThread extends Thread {
    private Object lock;
    public SynNotifyMethodThread(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        Service service = new Service();
        service.synNotifyMethod(lock);
    }
}

测试类

/**
 * Created by regis on 2017/4/20.
 */
public class Test {
    public static void main(String[] args) {
        Object lock = new Object();
        ThreadA a = new ThreadA(lock);
        a.start();
        ThreadA b = new ThreadA(lock);
        b.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SynNotifyMethodThread c = new SynNotifyMethodThread(lock);
        c.start();
    }
}

ThreadA类

/**
 * Created by regis on 2017/4/23.
 */
public class ThreadA extends Thread{
    private Object lock;
    public ThreadA(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        Service service = new Service();
        service.testMethod(lock);
    }
}

参考:http://www.cnblogs.com/hapjin/p/5492645.html

来自为知笔记(Wiz)

时间: 2024-11-01 10:58:24

java中wait和notify的关系的相关文章

java中父类与子类的关系以及使用

java中父类与子类的关系以及使用 在java中规定:一个父类可以有多个子类,但是一个子类只能有一个父类.子类可以通过extends关键字来继承父类.做个比较通俗的比喻,就像一个父亲可以有多个亲孩子,但是一个孩子只能有一个亲生父亲. 1.继承以及重写:子类继承父类是对父类属性和方法的全面继承,同时子类在继承了父类的方法后,可对父类的方法进行重写. public class Son extends Fat{ private int b; private String h1; public void

面试点:Java 中 hashCode() 和 equals() 的关系

Java 中 hashCode() 和 equals() 的关系是面试中的常考点,如果没有深入思考过两者设计的初衷,这个问题将很难回答.除了应付面试,理解二者的关系更有助于我们写出高质量且准确的代码. 一.基础:hashCode() 和 equals() 简介 在学习 hashCode() 和 equals() 之间的关系之前, 我们有必要先单独地了解他俩的特点. equals() equals() 方法用于比较两个对象是否相等,它与 == 相等比较符有着本质的不同. 在万物皆对象的 Java

Java中wait()和notify()方法的使用

1. wait方法和notify方法 这两个方法,包括notifyAll方法,都是Object类中的方法.在Java API中,wait方法的定义如下: public final void wait() throws InterruptedException Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this ob

java中接口与多重继承的关系

在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制.正是由于这两种机制的存在,才赋予了Java强大的 面向对象能力.abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进 行抽象类定义时对于abstract class和interface的选择显得比较随意.其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对 于问题领域本质的理解.对于设计意图的理解是否正确.合理

Java面试题:Java中的集合及其继承关系

关于集合的体系是每个人都应该烂熟于心的,尤其是对我们经常使用的List,Map的原理更该如此.这里我们看这张图即可: 1.List.Set.Map是否继承自Collection接口? List.Set 是,Map 不是.Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形. 2.阐述ArrayList.Vector.LinkedList的存储性能和特性. ArrayLi

java 中 热部署与卸载关系

今天发现早年在大象笔记中写的一篇笔记,之前放在ijavaboy上的,现在它已经访问不了了.前几天又有同事在讨论这个问题.这里拿来分享一下. 在web应用开发或者游戏服务器开发的过程中,我们时时刻刻都在使用热部署.热部署的目的很简单,就是为了节省应用开发和发布的时间.比如,我们在使用Tomcat或者Jboss等应用服务器开发应用时,我们经常会开启热部署功能.热部署,简单点来说,就是我们将打包好的应用直接替换掉原有的应用,不用关闭或者重启服务器,一切就是这么简单.那么,热部署到底是如何实现的呢?在本

Java中类名与文件名的关系

1.Java保存的文件名必须与类名一致: 2.如果文件中只有一个类,文件名必须与类名一致: 3.一个Java文件中只能有一个public类: 4.如果文件中不止一个类,文件名必须与public类名一致: 5.如果文件中不止一个类,而且没有public类,文件名可与任一类名一致. 当编写一个Java源代码文件时,此文件通常被称为编译单元(有时也称为转译单元).每个编译单元都必须要有一个后缀为.java,而在编译单元内测可以 有一个public类,该类的名称必须与文件名称相同(包括大小写,但不包括文

从语言设计的角度探究Java中hashCode()和equals()的关系

目录 一. 基础: hashCode()和equals()简介 二. 漫谈: 引入hashCode()与equals()之间的关系 三. 解密: 深入理解hashCode()和equals()之间的关系. 四. 验证: 结合HashMap的源码和官方文档, 验证两者的关系. 一. 基础: hashCode()和equals()简介 在学习hashCode()和equals()之间的关系之前, 我们有必要先单独了解他俩自身的特点. equals()方法用于比较两个对象是否相等, 它与"==&quo

Java中awt和swing的关系和区别

概述 awt是抽象组件窗口工具包,是Java最早的用于编写图形应用程序的开发包. Swing是为了补充awt的一些功能性的缺失问题而开发的包,以awt为基础的. 软件包 java.awt 的描述 包含用于创建用户界面和绘制图形图像的所有类.在 AWT 术语中,诸如按钮或滚动条之类的用户界面对象称为组件.Component 类是所有 AWT 组件的根.有关所有 AWT 组件的公共属性的详细描述,请参见 Component. 当用户与组件交互时,一些组件会激发事件.AWTEvent 类及其子类用于表