zoukankan      html  css  js  c++  java
  • wait、notify、notifyAll的阻塞和恢复

    前言:昨天尝试用Java自行实现生产者消费者问题(Producer-Consumer Problem),在coding时,使用到了Condition的await和signalAll方法,然后顺便想起了wait和notify,在开发中遇到了一个问题:wait、notify等阻塞和恢复的时机分别是什么?在网上Google了很久各种博文后,发现几乎没有人提到这个点。最后在官方文档中才找到了相应的介绍。

    (一)准备

      按照惯例应该是要先介绍一下wait、notify和notifyAll的基础知识。我找到了一篇不错的文章:《Java的wait(), notify()和notifyAll()使用小结》,它甚至介绍了为什么wait等方法为什么必须先获得对象锁。在这里我就不重复说了。

    (二)阻塞和恢复

    (1)wait方法

      wait方法继承自Object类(方法修饰符为fianl native,这也解释了为什么condition类中不能重写wait等方法),一共有三个方法:

    复制代码
    public final void wait(long timeout) 
                    throws InterruptedException
    
    public final void wait(long timeout, int nanos) 
                    throws InterruptedException
    
    public final void wait()
                    throws InterruptedException
    复制代码

      阻塞:这三个方法的调用都会使当前线程阻塞。该线程将会被放置到对该Object的请求等待队列中,然后让出当前对Object所拥有的所有的同步请求。线程会一直暂停所有线程调度,直到下面其中一种情况发生:

        ① 其他线程调用了该Object的notify方法,而该线程刚好是那个被唤醒的线程;

        ② 其他线程调用了该Object的notifyAll方法;

        ③ 其他对象中断/杀死了该线程;

        ④ (这种情况,只针对前两个方法)线程在等待指定的时间后;

      恢复:线程将会从等待队列中移除,重新成为可调度线程。它会与其他线程以常规的方式竞争对象同步请求。一旦它重新获得对象的同步请求,所有之前的请求状态都会恢复,也就是线程调用wait的地方的状态。线程将会在之前调用wait的地方继续运行下去。

    (2)notify和notifyAll方法

      notify的作用就是唤醒请求队列中的一个线程,而notifyAll唤醒的是请求队列中的所有线程。

      被唤醒的线程不会马上运行,除非获取了该Object的锁。也就是说,调用notify的线程,在调用notify后,不会像wait一样,马上阻塞线程的运行。而是继续运行,直到相应的线程调度完成或者让出Object的锁。而被唤醒的线程会在当前线程让出Object锁后,与其他线程以常规的方式竞争对象锁(正如上面提到的)。

    参考资料:

    https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

    public class WaitNotifyDemo {
        private volatile int val = 1;
        private Object o1= new Object();
        private Object o2= new Object();
    
        public class PrinterA implements Runnable {
            public void run() {
                while (val <= 3) {
                    synchronized (o2) {
                        try {
                            System.out.println("222222222");
                            o2.wait();
                            System.out.println("111111111");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        public class PrinterC implements Runnable {
            public void run() {
                while (val <= 3) {
                    synchronized (o2) {
                        try {
                            System.out.println("4444");
                            o2.wait();
                            System.out.println("3333");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        public class PrinterB implements Runnable {
            public void run() {
                while (val <= 30000) {
                    synchronized (o2) {
                        o2.notify();
    //                    o2.notifyAll();
                    }
                }
            }
        }
        public static void main(String[] args) {
            WaitNotifyDemo demo = new WaitNotifyDemo();
            demo.doPrint();
        }
    
        private void doPrint() {
            PrinterA pa = new PrinterA();
            Thread a = new Thread(pa);
            a.setName("printerA");
            a.start();
            PrinterC pc = new PrinterC();
            Thread c = new Thread(pc);
            c.setName("printerC");
            c.start();
            PrinterB pB = new PrinterB();
            Thread b = new Thread(pB);
            b.setName("printerA");
            b.start();
        }
    }
  • 相关阅读:
    Restful 的概念预览
    Bootstrap中alerts的用法
    Bootstrap HTML编码规范总结
    Bootstrap中img-circle glyphicon及js引入加载更快的存放位置
    PI数据库
    memcached
    Bootstrap中样式Jumbotron,row, table的实例应用
    js事件监听
    jquery显示隐藏操作
    HDU4521+线段树+dp
  • 原文地址:https://www.cnblogs.com/yaowen/p/6141807.html
Copyright © 2011-2022 走看看