zoukankan      html  css  js  c++  java
  • 等待与唤醒机制

    等待与唤醒机制

    1、线程间通信

    概念:多线程在处理同一个资源,但是处理的动作却不相同。

    image-20200505110208533

    为什么处理线程间通信?

    多线程并发执行时,在默认情况下CPU是随机切换线程的,当我们需要多线程来共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。

    如何保证线程间通信有效利用资源?

    多线程在处理同一个资源,并且任务不同时,需要线程通信来帮忙解决线程间对同一变量的使用或操作。就是多线程在操作同一份数据时,避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程能有效利用资源。而这种手段即——等待唤醒机制。

    2、等待唤醒机制

    概念:这是多线程间的协作机制。谈到线程我们经常想到的是线程间的竞争,比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在晋升的竞争,但更多时候你们更多是一起合作完成某些任务。

    就是在一个线程金信诺过了规定操作后,就进入等待状态(wait()),等待其他线程执行完他们的指定代码过后再将其唤醒(notify());在有多个线程进行等待时,如果需要,可以使用notify All()来唤醒所有的等待线程。wait/notify就是线程间的一种协作机制。

    image-20200505112417831

    等待唤醒中的方法:

    等待唤醒机制就是解决线程间通信的问题的,使用到的3个方法的含义如下:

    1、wait:线程不再活动,不再参与调度,进入wait set中,因此不会浪费cup资源,也不会去竞争锁了,这时的线程状态即是waiting。它还要等着别的线程执行一个特别的动作,就是通知(notify)在这个对象上等待的线程从wait set中释放出来,重新进入调度队列(ready queue)中。

    2、notify:则选取所有通知对象的wiat set 中的一个线程释放;例如,餐馆有空位置后,等候就餐最久的顾客最先入座。

    3、notifyAll:则释放所通知对象的wait set 上的全部线程。

    image-20200505113603685

    image-20200505113702505

    image-20200505114417315

    包子类:

    public class BaoZi {
      private String pi;
      private String xian;
      private boolean flag;

      public BaoZi() {
      }

      public BaoZi(String pi, String xian, boolean flag) {
          this.pi = pi;
          this.xian = xian;
          this.flag = 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;
      }
    }

    包子铺:

    public class BaoZiPu implements Runnable {
      private BaoZi bz;

      public BaoZiPu() {
      }

      public BaoZiPu(BaoZi bz) {
          this.bz = bz;
      }

      //生产包子
      @Override
      public void run() {
          int count = 0;
          while (true){
              synchronized (bz){
                  //对包子的状态进行判断
                  if (bz.isFlag()){
                      //包子铺调用wait方法进入等待状态,让客人吃包子
                      try {
                          bz.wait();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
                  //被唤醒之后执行,包子铺生产包子
                  if (count%2==0){
                      bz.setPi("薄皮");
                      bz.setXian("三鲜");
                  }else{
                      bz.setPi("厚皮");
                      bz.setXian("牛肉大葱");
                  }
                  count++;
                  System.out.println("包子铺正在生产:"+bz.getPi()+bz.getXian()+"包子");
                  //生产包子
                  try {
                      Thread.sleep(3000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  //包子好了后,修改状态
                  bz.setFlag(true);
                  bz.notify();//唤醒客人的线程
                  System.out.println("包子生产完毕");
              }
          }
      }
    }

    客人:

    public class ChiHuo implements Runnable {
      private BaoZi baoZi;

      public ChiHuo() {
      }

      public ChiHuo(BaoZi baoZi) {
          this.baoZi = baoZi;
      }

      public BaoZi getBaoZi() {
          return baoZi;
      }

      public void setBaoZi(BaoZi baoZi) {
          this.baoZi = baoZi;
      }

      @Override
      public void run() {
          while (true){
              synchronized (baoZi){
                  if(baoZi.isFlag()==false){
                      //客人等待包子做好
                      try {
                          baoZi.wait();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
                  //唤醒之后,吃包子
                  System.out.println("吃"+baoZi.getPi()+baoZi.getXian()+"的包子");
                  baoZi.setFlag(false);//包子吃完了
                  baoZi.notify();//唤醒去做包子
                  System.out.println("包子吃完了");
              }
          }
      }
    }

    测试:

    public class Demo05Main {
      public static void main(String[] args) {
          //创建包子对象
          BaoZi baoZi = new BaoZi();

          BaoZiPu baoZiPu = new BaoZiPu(baoZi);
          new Thread(baoZiPu).start();
          ChiHuo chiHuo = new ChiHuo(baoZi);
          new Thread(chiHuo).start();
      }
    }

     

  • 相关阅读:
    从零开始学习Sencha Touch MVC应用之二
    PHPMailer IIS下的PHP脚本使用GMAIL发送邮件PHP
    php群发邮件
    PHP编辑器
    PHP使用GET传输汉字的编码转换
    转一个手机开发的帖子(来自开发者俱乐部)
    Zend_Mail收发smtp(gmail,163)邮件Zend Framework
    just a simple for a mail() amd get array()
    ecshop二次开发 结构分析和代码研究 呵呵
    如何重置Drupal 7的用户密码
  • 原文地址:https://www.cnblogs.com/lxy522/p/12831816.html
Copyright © 2011-2022 走看看