• 线程间通信 | 等待唤醒机制


    1.线程间通信

    2.等待唤醒机制

    3.等待唤醒案例

    3.1简单生产者消费者案例

    分析:

    代码:

    Object类中的方法
        void wait()   导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
        void notify() 唤醒正在等待对象监视器的单个线程。

    package com.goldencis.thread;
    /**
     * 等待唤醒案例 :线程之间的通信
     *     创建一个顾客进程(消费者):告知老板要的包子的种类和数量,调用wait方法,放弃cpu的执行,进入waiting状态(无限等待)
     *     创建一个老板进程(生产者):花费5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子
     *
     * 注意:
     *    顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只有一个在执行
     *    同步使用的锁对象必须保证唯一
     *    只有锁对象才能调用wait和notify方法
     *
     * Object类中的方法
     *  void wait()   导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
     *  void notify() 唤醒正在等待对象监视器的单个线程。
     */
    public class DemoWaitAndNotify {
        public static void main(String[] args) {
            //锁对象
            Object obj = new Object();
     
            //创建一个顾客进程(消费者)
            new Thread(){
                @Override
                public void run() {
                   synchronized (obj){
                     while(true){
                         //告知老板要的包子的种类和数量
                         System.out.println("告知老板要的包子的种类和数量");
                         //调用wait方法,放弃cpu的执行,进入waiting状态(无限等待)
                         try {
                             obj.wait();
                         } catch (InterruptedException e) {
                             e.printStackTrace();
                         }
                         System.out.println("吃包子咯");
                     }
                   }
                }
            }.start();
     
            //创建一个老板进程(生产者)
            new Thread(){
                //做好包子之后,调用notify方法,唤醒顾客吃包子
                @Override
                public void run() {
                   while(true){
                       //花费5秒做包子,
                       try {
                           Thread.sleep(5000);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       synchronized (obj){
                           System.out.println("老板花费5秒做包子,唤醒顾客吃包子");
                           obj.notify();
                       }
                   }
                }
            }.start();
        }
    }

     进入计时等待有两种方式:
        sleep(long m)    在毫秒值结束之后,线程睡醒进入Runnable/Blocked状态

        wait(long m)      如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒进入Runnable/Blocked状态

    唤醒方式:
        notify()               唤醒正在等待对象监视器的单个线程

        notifyAll()           唤醒正在等待对象监视器的所有线程

    3.2 生产者与消费者案例

    分析:

    代码:

    包子类Bun.java

    package com.goldencis.thread.BunPAC;
     
    /**
     * 包子类
     */
    public class Bun {
        String pi;
        String xian;
        boolean flag;//包子资源是否存在
     
        public String getPi() {
            return pi;
        }
     
        public void setPi(String pi) {
            this.pi = pi;
        }
     
        public String getXian() {
            return xian;
        }
     
        public void setXian(String xian) {
            this.xian = xian;
        }
     
        public boolean isFlag() {
            return flag;
        }
     
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    }

    生产者Producer.java

    package com.goldencis.thread.BunPAC;
    /**
     * 生产者
     */
    public class Producer extends Thread{
        private Bun bun;//包子
        private Object obj;//锁对象
     
        public Producer(Bun bun, Object obj) {
            this.bun = bun;
            this.obj = obj;
        }
     
        @Override
        public void run() {
           while(true){
               synchronized (obj){
                   //没有包子,生产包子
                   if(bun.flag == false){
                       try {
                           Thread.sleep(2000);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       System.out.println("包子铺生产了一个包子");
                       bun.flag = true;
                       obj.notify();//唤醒消费者
                   // 有包子,等待
                   }else{
                       try {
                           obj.wait();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }
           }
        }
    }

    Consumer.java

    package com.goldencis.thread.BunPAC;
    /**
     * 消费者
     */
    public class Consumer extends Thread{
        private Bun bun;//包子
        private Object obj;//锁对象
     
        public Consumer(Bun bun, Object obj) {
            this.bun = bun;
            this.obj = obj;
        }
     
        @Override
        public void run() {
           while (true){
               synchronized (obj){
                   //有包子,吃包子
                   if(bun.flag == true){
                       System.out.println("吃包子咯");
                       bun.flag = false;
                       obj.notify();//唤醒生产者
                   //没有包子,等待
                   }else{
                       try {
                           obj.wait();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }
           }
        }
    }

    测试类Test.java

    package com.goldencis.thread.BunPAC;
     
    public class Test {
        public static void main(String[] args) {
            Bun bun =new Bun();
            bun.setFlag(false);
            Object obj = new Object();
            Producer p = new Producer(bun,obj);
            Consumer c = new Consumer(bun,obj);
            p.start();
            c.start();
        }
    }

    注:可以把包子(bun)作为锁对象,就不用创建Object对象了

  • 相关阅读:
    setTimeout和setInterval的区别(面试题)
    什么是跨域?列出几种JS跨域解决方法?(前端面试题)
    建网站的流程
    CSS Sprite(雪碧图)简单使用
    前端不得不说的性能优化
    面试题
    前端如何做好SEO优化
    JavaScript string字符串对象常见方法
    微信号复制跟跳转——clipboard.js
    微信号复制跟跳转——execCommand()
  • 原文地址:https://www.cnblogs.com/sx66/p/14308550.html
Copyright © 2020-2023  润新知