zoukankan      html  css  js  c++  java
  • 03.线程的通知notify与等待wait

    wait()、notify、notifyAll()方法

    wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。
    这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。

    • 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
    • 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
    • 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
      注意:一定要在线程同步中使用,并且是同一个锁的资源
    public class NotifyAllDemo {
        private static volatile Object reA = new Object();
       public static void main(String[] args) throws InterruptedException{
           Thread threadA = new Thread(new Runnable() {
               @Override
               public void run() {
                   synchronized (reA){
                       System.out.println("threadA get reA lock");
                       try {
                           System.out.println("threadA begin wait");
                           reA.wait();
                           System.out.println("threadA end wait");
                       }catch (InterruptedException e){
                           e.printStackTrace();
                       }
                   }
               }
           });
           Thread threadB = new Thread(new Runnable() {
               @Override
               public void run() {
                   synchronized (reA){
                       System.out.println("threadB get reA lock");
                       try {
                           System.out.println("threadB begin wait");
                           reA.wait();
                           System.out.println("threadB end wait");
                       }catch (InterruptedException e){
                           e.printStackTrace();
                       }
                   }
               }
           });
           Thread threadC = new Thread(new Runnable() {
               @Override
               public void run() {
                   synchronized (reA){
                       System.out.println("threadC begin notify");
                       //reA.notify();
                       reA.notifyAll();
                   }
               }
           });
           threadA.start();
           threadB.start();
           Thread.sleep(1000);
           threadC.start();
           threadA.join();
           threadB.join();
           threadC.join();
           System.out.println("main over");
    
           //调用notify()
           //threadA get reA lock
           //threadA begin wait
           //threadB get reA lock
           //threadB begin wait
           //threadC begin notify
           //threadA end wait
    
           //调用notifyAll()
           //threadA get reA lock
           //threadA begin wait
           //threadB get reA lock
           //threadB begin wait
           //threadC begin notify
           //threadA end wait
           //threadB end wait
           //main over
           
           //在线程 B 调用共享变量的 wait()方法前线程C调用了共享变量的 notifyAll 方法, 这样,只有线程 A 被唤醒,而线程 B 并没有被唤醒, 还是处于阻塞状态
       }
    }
    

    补充

    /**
     * p56
        线程T1             线程T2
     取得Object监视器
     Object.wait()
     释放Object监视器
                        取得Object监视器
                        Object.notify()
     等待Object监视器    释放Object监视器
     重获Object监视器
     继续执行
     *
     * T1在正确执行wait()方法前,首先必须获得object对象的监视器,而wait()方法在执行后,会释放这个监视器,这样做的
     * 目的是使得其他等待在object对象上的线程不至于因为T1的休眠而全部无法正常执行。
     * 线程T2在notify()调用前,必须获得object的监视器,T1已经释放了这个监视器,因此,T2可以顺利获得object的监视器。
     * 接着,T2执行了notify()方法尝试唤醒一个等待线程,这里假设唤醒了T1,T1在被唤醒后,要做的第一件事并不是执行后续的代码,
     * 而是要尝试重新获得object的监视器,而这个监视器也正是T1在wait()方法执行前所持有的那个。如果暂时无法获得,T1还必须
     * 要等待这个监视器,当监视器顺利获得后,T1才可以真正意义上的继续执行。
     */
    public class WaitAndNotifyDemo {
        final static Object object = new Object();
        public static class T1 extends Thread{
            @Override
            public void run() {
                synchronized (object){
                    System.out.println(System.currentTimeMillis()+":T1 start!");
                    try {
                        System.out.println(System.currentTimeMillis()+":T1 wait for object");
                        object.wait();//执行后,T1会进行等待,并释放object的锁
                        } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(System.currentTimeMillis()+":T1 end!");
                }
            }
        }
        public static class T2 extends Thread{
            @Override
            public void run() {
                synchronized (object){
                    System.out.println(System.currentTimeMillis()+":T2 start!notify one thread");
                    object.notify();
                    System.out.println(System.currentTimeMillis()+":T2 end!");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        public static void main(String[] args){
            Thread t1 = new T1();
            Thread t2 = new T2();
            t1.start();
            t2.start();
            //1566261979660:T1 start!
            //1566261979660:T1 wait for object
            //1566261979660:T2 start!notify one thread
            //1566261979660:T2 end!  //此时会卡秒,更明显地说明T1在得到notify()通知后,还是会先尝试重新获得object的对象锁
            //1566261981665:T1 end!
    
            /**
             * object.wait()与Thead.sleep()区别:
             * wait()可以被唤醒,会释放目标对象的锁,而Thead.sleep()方法不会释放任何资源
             */
        }
    }
    
    
    /**
     * 模拟过时的挂起(suspend),继续执行(resume)
     */
    public class WaitAndNotifyDemo2 {
        public static Object object = new Object();
        public static class ChangeObjectThead extends Thread{
           volatile boolean suspendme = false;
           //挂起线程
           public void suspendMe(){
               suspendme = true;
           }
           //继续执行线程
           public void resumeMe(){
               suspendme = false;
               synchronized (this){
                   notify();
               }
           }
            @Override
            public void run() {
               while (true){
                   synchronized (this){
                       //先检查是否被挂起,如果是,则执行wait()方法进行等待,否则进行正常的处理
                       while (suspendme){
                           try {
                               wait();
                           } catch (InterruptedException e) {
                               e.printStackTrace();
                           }
                       }
                       synchronized (object){
                           System.out.println("in ChangeObjectThread");
                       }
                       Thread.yield();
                   }
               }
            }
        }
        public static class ReadObjectThread extends Thread{
            @Override
            public void run() {
                while (true){
                    synchronized (object){
                        System.out.println("in ReadObjectThread");
                    }
                    Thread.yield();
                }
            }
        }
        public static void main(String[] args) throws InterruptedException{
            ChangeObjectThead t1 = new ChangeObjectThead();
            ReadObjectThread t2 = new ReadObjectThread();
            t1.start();
            t2.start();
            Thread.sleep(1000);
            System.out.println("t1 suspendMe");
            t1.suspendMe();
            Thread.sleep(2000);
            System.out.println("t1 resumeMe");
            t1.resumeMe();
            //in ChangeObjectThread
            //in ReadObjectThread
            //in ChangeObjectThread
            //...
            //in ReadObjectThread
            //in ReadObjectThread
            //in ReadObjectThread
            //in ReadObjectThread
            //in ReadObjectThread
            //in ReadObjectThread
            //...
            //in ReadObjectThread
            //in ChangeObjectThread
            //in ReadObjectThread
            //in ChangeObjectThread
            //in ReadObjectThread
            //in ChangeObjectThread
        }
    }
    
  • 相关阅读:
    黑马程序员-winform视频总结的一些知识点
    如何让360兼容模式打开网页和极速模式打开一样
    [2016-10-24]jQuery学习回顾笔记1.0
    鼠标上下滑动总是放大缩小页面,按住ctrl+0
    按钮在苹果手机显示不正常
    鼠标悬停图片放大
    关于高度
    如何做出透明背景的flash动画
    复选框css
    HTML CSS 特殊字符表(转载)
  • 原文地址:https://www.cnblogs.com/fly-book/p/11361616.html
Copyright © 2011-2022 走看看