一 java线程的等待/通知模型

九章
• 阅读 1353

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

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

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

/**
 * 买小米5手机
 * @author zhanghongjun
 *
 */
public class BuyXiaoMi5 {
    static boolean hasXiaoMi5 = false;
    static Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        //消费者
        Thread miFansThread = new Thread(new MiFans(),"MiFans");

        //生产者
        Thread leiBS = new Thread(new LeiBuShi(),"LeiBuShi");

        miFansThread.start();
        leiBS.start();

    }

    /**
     * 雷布斯,生产者
     * @author zhanghongjun
     *
     */
    static class LeiBuShi implements Runnable{
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println("Are you ok ? 我们开始生产小米5了,大家等一等啊");
                try {
                    System.out.println("Are you ok ? 小米5手机生产ing中,大家等一等啊");
                    Thread.sleep(3000); //6个月后,小米5终于上市了
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Are you ok? 小米5上市啦,大家可以哄抢啦");
                lock.notifyAll();    //通知所有的人,可以抢手机了
                hasXiaoMi5 = true;    //终于有小米5手机了
            }
        }

    }


    /**
     * 米粉,消费者
     * @author zhanghongjun
     *
     */
    static class MiFans implements Runnable{
        @Override
        public void run() {
            synchronized (lock) {
                //没有小米5手机,只有等待了
                while(!hasXiaoMi5){
                    System.out.println("雷军耍猴,不知道要等多久,才能买到小米5...");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

            System.out.println("我是米粉,终于买到一台发烧的小米5了,开森中。。。");
        }
    }

}

上面代码可以看到,开始的时候,米粉线程要买小米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()

}

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

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
2星期前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
九章 九章
3年前
二 Java利用等待/通知机制实现一个线程池
接着上一篇博客的一Java线程的等待/通知模型(http://www.cnblogs.com/start1225/p/5866575.html"一java线程的等待/通知模型") ,没有看过的建议先看一下。下面我们用等待通知机制来实现一个线程池.(https://www.helloworld.net/p/XJXfgbimvcjd)本
Wesley13 Wesley13
2年前
4、jstack查看线程栈信息
1、介绍利用jps、top、jstack命令找到进程中耗时最大的线程,以及线程状态等等,同时最后还可以显示出死锁的线程查找:FoundoneJavaleveldeadlock即可1、jps获得进程号!(https://oscimg.oschina.net/oscnet/da00a309fa6
Wesley13 Wesley13
2年前
Java并发 wait()、notify()和notifyAll()
一个线程修改一个对象的值,而另一个线程则感知到了变化,然后进行相应的操作,这就是wait()、notify()和notifyAll()方法的本质。具体体现到方法上则是这样的:一个线程A调用了对象obj的wait方法进入到等待状态,而另一个线程调用了对象obj的notify()或者notifyAll()方法,线程A收到通知后从对象obj的wait方法返回,继续
Wesley13 Wesley13
2年前
03.Android崩溃Crash库之ExceptionHandler分析
目录总结00.异常处理几个常用api01.UncaughtExceptionHandler02.Java线程处理异常分析03.Android中线程处理异常分析04.为何使用setDefaultUncaughtExceptionHandler前沿上一篇整体介绍了crash崩溃
Wesley13 Wesley13
2年前
Java中生产者与消费者模式
 生产者消费者模式首先来了解什么是生产者消费者模式。该模式也称有限缓冲问题(英语:Boundedbufferproblem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同
Wesley13 Wesley13
2年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
2年前
Java多线程之线程协作
常见的线程协作方式是:生产者/消费者。一个线程作为生产者,生产要处理数据,比如拿一个线程来生产Order,用户每下一单,此线程就生产一个Order对象。设置一个仓库,来存放生产出来的Order对象。一个线程作为消费者,消费|处理仓库中的Order对象(打印订单、拣货、发货)。demo  订单处理流程1、用
Wesley13 Wesley13
2年前
Java并发编程原理与实战二十三:Condition原理分析
先来回顾一下java中的等待/通知机制我们有时会遇到这样的场景:线程A执行到某个点的时候,因为某个条件condition不满足,需要线程A暂停;等到线程B修改了条件condition,使condition满足了线程A的要求时,A再继续执行。自旋实现的等待通知最简单的实现方法就是将condition设为一个volatile的变量