当前位置:  编程技术>java/j2ee

Java的wait(), notify()和notifyAll()使用心得

    来源: 互联网  发布时间:2014-10-27

    本文导语:  wait(),notify()和notifyAll()都是java.lang.Object的方法:wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.notify(): Wakes up a single thread that is waiting on this object's monitor.notifyAll(): Wakes up all...

wait(),notify()和notifyAll()都是java.lang.Object的方法:
wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
notify(): Wakes up a single thread that is waiting on this object's monitor.
notifyAll(): Wakes up all threads that are waiting on this object's monitor.
这三个方法,都是Java语言提供的实现线程间阻塞(Blocking)和控制进程内调度(inter-process communication)的底层机制。在解释如何使用前,先说明一下两点:
1. 正如Java内任何对象都能成为锁(Lock)一样,任何对象也都能成为条件队列(Condition queue)。而这个对象里的wait(), notify()和notifyAll()则是这个条件队列的固有(intrinsic)的方法。
2. 一个对象的固有锁和它的固有条件队列是相关的,为了调用对象X内条件队列的方法,你必须获得对象X的锁。这是因为等待状态条件的机制和保证状态连续性的机制是紧密的结合在一起的。
(An object's intrinsic lock and its intrinsic condition queue are related: in order to call any of the condition queue methods on object X, you must hold the lock on X. This is because the mechanism for waiting for state-based conditions is necessarily tightly bound to the mechanism fo preserving state consistency)
根据上述两点,在调用wait(), notify()或notifyAll()的时候,必须先获得锁,且状态变量须由该锁保护,而固有锁对象与固有条件队列对象又是同一个对象。也就是说,要在某个对象上执行wait,notify,先必须锁定该对象,而对应的状态变量也是由该对象锁保护的。
知道怎么使用后,我们来问下面的问题:
1. 执行wait, notify时,不获得锁会如何?
请看代码:
代码如下:

public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        obj.wait();
        obj.notifyAll();
}

执行以上代码,会抛出java.lang.IllegalMonitorStateException的异常。
2. 执行wait, notify时,不获得该对象的锁会如何?
请看代码:
代码如下:

public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Object lock = new Object();
        synchronized (lock) {
            obj.wait();
            obj.notifyAll();
        }
    }

执行代码,同样会抛出java.lang.IllegalMonitorStateException的异常。
3. 为什么在执行wait, notify时,必须获得该对象的锁?
这是因为,如果没有锁,wait和notify有可能会产生竞态条件(Race Condition)。考虑以下生产者和消费者的情景:
1.1生产者检查条件(如缓存满了)-> 1.2生产者必须等待
2.1消费者消费了一个单位的缓存 -> 2.2重新设置了条件(如缓存没满) -> 2.3调用notifyAll()唤醒生产者
我们希望的顺序是: 1.1->1.2->2.1->2.2->2.3
但在多线程情况下,顺序有可能是 1.1->2.1->2.2->2.3->1.2。也就是说,在生产者还没wait之前,消费者就已经notifyAll了,这样的话,生产者会一直等下去。
所以,要解决这个问题,必须在wait和notifyAll的时候,获得该对象的锁,以保证同步。
请看以下利用wait,notify实现的一个生产者、一个消费者和一个单位的缓存的简单模型:
代码如下:

public class QueueBuffer {
    int n;
    boolean valueSet = false;
    synchronized int get() {
        if (!valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }
    synchronized void put(int n) {
        if (valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        valueSet = true;
        System.out.println("Put: " + n);
        notify();
    }
}

代码如下:

public class Producer implements Runnable {
    private QueueBuffer q;
    Producer(QueueBuffer q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while (true) {
            q.put(i++);
        }
    }
}

代码如下:

public class Consumer implements Runnable {
    private QueueBuffer q;
    Consumer(QueueBuffer q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while (true) {
            q.get();
        }
    }
}

代码如下:

public class Main {
    public static void main(String[] args) {
        QueueBuffer q = new QueueBuffer();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control-C to stop.");
    }
}

所以,JVM通过在执行的时候抛出IllegalMonitorStateException的异常,来确保wait, notify时,获得了对象的锁,从而消除隐藏的Race Condition。
最后来看看一道题:写一个多线程程序,交替输出1,2,1,2,1,2......
利用wait, notify解决:
代码如下:

public class OutputThread implements Runnable {
    private int num;
    private Object lock;
    public OutputThread(int num, Object lock) {
        super();
        this.num = num;
        this.lock = lock;
    }
    public void run() {
        try {
            while(true){
                synchronized(lock){
                    lock.notifyAll();
                    lock.wait();
                    System.out.println(num);
                }
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        final Object lock = new Object();
        Thread thread1 = new Thread(new OutputThread(1,lock));
        Thread thread2 = new Thread(new OutputThread(2, lock));
        thread1.start();
        thread2.start();
    }
}

    
 
 

您可能感兴趣的文章:

  • java命名空间java.lang类object的类成员方法: notifyall定义及介绍
  • 基于Java多线程notify与notifyall的区别分析
  • 浙ICP备11055608号-3 iis7站长之家
  • 菜鸟问JAVA高手,对thinking in Java!有何心得!
  • 大家谈谈学习JAVA的心得好吗?
  • 各位大虾,能否给兄弟提供一些自己认为比较好的关于java学习的电子书刊的下载地址和关于java学习的心得体会?欢迎讨论
  • JAVA心得分享---return语句的用法
  • 大家能不能介绍一下自己的学习JAVA的心得?必送分
  • java中的移位运算符心得总结
  • Java多线程yield心得分享
  • 各位看<think in java>第二版英文版,有什么心得吗?我英文不好,借助金山词霸,看的速度还超慢,好像一共有一千多页,不知道啥时候才能看完
  • Java排序实现的心得分享
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 使用java jdk中的LinkedHashMap实现简单的LRU算法
  • MySocketServer.java 使用或覆盖一个不鼓励使用的API???
  • java将类序列化并存储到mysql(使用hibernate)
  • JAVA中不赞成使用(Deprecated)的方法是否可以使用
  • 各位使用过JAVA的朋友们!JAVA好用吗?它有向VC那样的集成开发环境吗?
  • java 可以使用 可是javac不可以使用。老兄帮帮忙
  • 哪位知道如何用JAVA进行图形文件的缩放? 是使用JAVA2D 或是有第三方的软件?
  • java堆栈类使用实例(java中stack的使用方法)
  • env查看环境变量,JAVA_HOME明明在里面,但使用nutch时还是提示JAVA_HOME not set?
  • 如何使用linux下的java编译器????
  • 如何使用java这个命令?
  • 为什么使用cat输出的文本文件是中文的,使用java从文件读取出来时显示的是乱码?
  • linux 远程上使用java
  • UNIX下使用java运行class的问题
  • java:sun公司的联机帮助如何使用?
  • 请教如何使用Java编写的Applet程序关闭浏览器??
  • 怎么使用 JAVA 的包呀???
  • 针对使用java进行硬件编程
  • 使用editplus编写java如何编译成字节码文件,如何解释
  • 谁能告诉我哪里能找到java包内部类及方法使用介绍
  • 使用java时间的调查,谢谢大家
  • java命名空间java.sql类types的类成员方法: java_object定义及介绍
  • 我想学JAVA ,是买THINK IN JAVA 还是JAVA2核心技术:卷1 好???
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: imageflavor定义及介绍
  • 请问Java高手,Java的优势在那里??,Java主要适合于开发哪类应用程序
  • java命名空间java.lang.management类managementfactory的类成员方法: getcompilationmxbean定义及介绍
  • 如何将java.util.Date转化为java.sql.Date?数据库中Date类型对应于java的哪个Date呢
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getlibrarypath定义及介绍
  • 谁有电子版的《Java编程思想第二版(Thinking in java second)》和《Java2编程详解(special edition java2)》?得到给分
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getstarttime定义及介绍
  • 本人想学java,请问java程序员的待遇如何,和java主要有几个比较强的方向


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3