zoukankan      html  css  js  c++  java
  • 一 java线程的等待/通知模型

    java 中线程之间的通信问题,有这么一个模型:一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另一个线程。前者是生产者,后者就是消费者,也可以叫做生产者-消费者问题

    生产者生产了产品,如何通知消费者?下面就介绍下java线程中的等待-通知机制。其它语言类似,自行研究。代码附上

    下面是以买小米5手机为例子,来说明等待通知机制

     1 /**
     2  * 买小米5手机
     3  * @author zhanghongjun
     4  *
     5  */
     6 public class BuyXiaoMi5 {
     7     static boolean hasXiaoMi5 = false;
     8     static Object lock = new Object();
     9     
    10     public static void main(String[] args) throws InterruptedException {
    11         //消费者
    12         Thread miFansThread = new Thread(new MiFans(),"MiFans");
    13         
    14         //生产者
    15         Thread leiBS = new Thread(new LeiBuShi(),"LeiBuShi");
    16         
    17         miFansThread.start();
    18         leiBS.start();
    19         
    20     }
    21     
    22     /**
    23      * 雷布斯,生产者
    24      * @author zhanghongjun
    25      *
    26      */
    27     static class LeiBuShi implements Runnable{
    28         @Override
    29         public void run() {
    30             synchronized (lock) {
    31                 System.out.println("Are you ok ? 我们开始生产小米5了,大家等一等啊");
    32                 try {
    33                     System.out.println("Are you ok ? 小米5手机生产ing中,大家等一等啊");
    34                     Thread.sleep(3000); //6个月后,小米5终于上市了
    35                 } catch (InterruptedException e) {
    36                     e.printStackTrace();
    37                 }
    38                 
    39                 System.out.println("Are you ok? 小米5上市啦,大家可以哄抢啦");
    40                 lock.notifyAll();    //通知所有的人,可以抢手机了
    41                 hasXiaoMi5 = true;    //终于有小米5手机了    
    42             }
    43         }
    44         
    45     }
    46     
    47     
    48     /**
    49      * 米粉,消费者
    50      * @author zhanghongjun
    51      *
    52      */
    53     static class MiFans implements Runnable{
    54         @Override
    55         public void run() {
    56             synchronized (lock) {
    57                 //没有小米5手机,只有等待了
    58                 while(!hasXiaoMi5){
    59                     System.out.println("雷军耍猴,不知道要等多久,才能买到小米5...");
    60                     try {
    61                         lock.wait();
    62                     } catch (InterruptedException e) {
    63                         e.printStackTrace();
    64                     }
    65                 }
    66             }
    67             
    68             System.out.println("我是米粉,终于买到一台发烧的小米5了,开森中。。。");
    69         }
    70     }
    71     
    72 }

    上面代码可以看到,开始的时候,米粉线程要买小米5手机,结果条件不满足,hasXiaoMi5 = false; 当条件不满足的时候,就需要等待, lock.wait();

    此时线程进入等待队列中,线程会阻塞,需要注意   lock.wait() ,是会释放锁的,进而进入到线程的等待队列中,这时候,因为wait()已经释放了锁,所以,LeiBuShi 线程就可以

    获得锁,进而去生产手机,等到手机生产出来以后,既 hasXiaoMi5 = true了,这时候就通知在此锁上等待的线程,lock.notify()或者lock.notifyAll,之后,离开同步块,进而释放锁,这时候 61行,lock.wait() 函数返回,条件成立,进而继续向下运行,买到手机。

    这里需要注意的几点如下:

    1  使用wait(),notify(),notifyAll()时需要先对调用对象加锁

    2  调用wait()方法后,线程状态由Running状态变为 waiting状态,并将当前线程放置到线程的等待队列中

    3 notify()或者notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或者nofityAll()的线程释放锁之后,等待线程才有机会从wait()返回

    4 从wait()方法返回的前提是获得了调用对象的锁.

    等待/通知的经典范式

    等待方步骤如下:

    1 获取对象的锁

    2 如果条件满足,那么调用对象的wait()方法,被通知后仍要检查条件。

    3 条件满足则执行相应的业务逻辑

    对应的伪代码如下:

    synchronized(对象){

      while(条件不满足时){

            对象.wait()

      }

         对应的逻辑

    }

    通知方步骤如下:

    1 获得对象的锁

    2 改变条件 

    3 通知所有等待对象上的线程

    对应的伪代码如下:

    synchronized(对象){

      改变条件

      对象.notifyAll()

    }

    以上就是典型的通知等待机制。能力有限,希望对大家有所帮助

    欢迎访问作者的helloworld的个人博客:
    https://www.helloworld.net/jiulu

    同时也可以加作者的微信:daitukeji
    也可以扫下面的二维码添加
    ![image](https://img-hello-world.oss-cn-beijing.aliyuncs.com/imgs/f0b62fd75da7cbeba3b77965f4e26845.png)

  • 相关阅读:
    Go-15-flag.String 获取系统参数
    Go-14-解决 go get golang.org/x/text 拉取失败问题
    Go-08-函数与指针
    redis 学习(6)-- 集合类型
    redis 学习(5)-- 列表类型
    redis 学习(4)-- 哈希类型
    redis 学习(3)-- String 类型
    redis 学习(二)-- 通用命令
    redis 学习(1)-- redis 安装与启动
    Mysql 索引原理及优化
  • 原文地址:https://www.cnblogs.com/start1225/p/5866575.html
Copyright © 2011-2022 走看看