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

九章 等级 384 0 0

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()

}

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

收藏
评论区

相关推荐

.NET C#到Java没那么难,DB篇
.NET C到Java没那么难,DB篇 .NET C到Java没那么难,DB篇 前言 .NET C到Java没那么难,都是面向对象的语言,而且语法还是相似的,先对比一下开发环境,再到Servlet,再到
.NET C#到Java没那么难,MVC篇
.NET C到Java没那么难,MVC篇 .NET C到Java没那么难,MVC篇 最典型的JAVA MVC就是JSP servlet javabean的模式。比较好的MVC,老牌的有Struts、
.NET C#到Java没那么难,Servlet篇
.NET C到Java没那么难,Servlet篇 .NET C到Java没那么难,Servlet篇 前言 .NET C到Java没那么难,都是面向对象的语言,而且语法还是相似的,先对比一下开发
Linux下安装jdk
一 、安装前 java 1.查看是否已安装JDK yum list installed |grep java 2.卸载CentOS系统Java环境 yum y remove java1.8.0openjdk 表示卸载所有openjdk相关文件输入 yum y remove tzdatajava.noarch 卸载t
Java中的浮点数四舍五入到小数点后2位的几种方法
前言 四舍五入到2或3个小数位是我们Java程序员日常开发中肯定会遇到。幸运的是,Java API提供了几种在Java中舍入数字的方法 我们可以使用Math.round(),BigDecimal或DecimalFormat将Java中的任何浮点数四舍五入到n个位置。我个人更喜欢使用BigDecimal在Java中四舍五入任何数字,因为它具有便捷的API并
Groovy初探
开始之前 了解本教程的主要内容,以及如何从中获得最大收获。 关于本教程 如果现在有人要开始完全重写 Java,那么 Groovy 就像是 Java 2.0。Groovy 并没有取代 Java,而是作为 Java 的补充,它提供了更简单、更灵活的语法,可以在运行时动态地进行类型检查。您可以使用 Groovy 随意编写 Java 应用程序,连接 Java
《java 核心技术》卷1 学习 概述 第一章Java程序设计概述
从浅面了解Java 1.Java 在语言得地位 现在有所下降 但仍是老大哥 所以值得学习 2.Java特性 1.简单性:从一方面来说 Java可以支持在小型机器上运行 必定不是很复杂得,所以上手不难 2.面向对象:Java有相比于其他的语言 更简单得接口
一 java线程的等待/通知模型
java 中线程之间的通信问题,有这么一个模型:一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另一个线程。前者是生产者,后者就是消费者,也可以叫做生产者消费者问题 生产者生产了产品,如何通知消费者?下面就介绍下java线程中的等待通知机制。其它语言类似,自行研究。代码附上 下面是以买小
Java里面的十万个为什么
Java里面的十万个为什么 1.不是说 JVM 是运行 Java 程序的虚拟机吗?那 JRE 和 JVM 的关系是怎么样的呢?简单地说,JRE 包含 JVM 。JVM 是运行 Java 程序的核心虚拟机,而运行 Java 程序不仅需要核心虚拟机,还需要其他的类加载器,字节码校验器以及大量的基础类库。JRE 除包含 JVM 之外,还包含运行 Java 程序的其
Java学习路线
阶段一 (夯实基础)Java基础语法学习目标:1.熟悉Java等基本概念2.掌握Eclipse/IDEA集成开发工具的安装、配置和应用3.熟悉Java基本语法、基本类型、运算符和表达式4.掌握分支、循环逻辑语句、数组等知识的应用知识点列表:JDK、JRE、JVM基本概念Java环境搭建和配置安装和使用Eclipse/IDEA开发环境Java基本数据类型变量,
Java开发面试高频考点学习笔记(每日更新)
Java开发面试高频考点学习笔记(每日更新) 1.深拷贝和浅拷贝 2.接口和抽象类的区别 3.java的内存是怎么分配的 4.java中的泛型是什么?类型擦除是什么? 5.Java中的反射是什么 6.序列化与反序列化 7.Object有哪些方法? 8.JVM内存模型 9.类加载机制 10.对象的创建和对象的布局 11.Java的四种引用
2021年度最全面JVM虚拟机,类加载过程与类加载器
前言类装载器子系统是JVM中非常重要的部分,是学习JVM绕不开的一关。一般来说,Java 类的虚拟机使用 Java 方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表
秋招已经开始准备了!【Java面试题】最新Java开发岗面试知识笔记
在最近两个月不断的面试中,我分类总结了 Java 开发岗位面试中的一些知识点。主要包括以下几个部分: 1. Java 基础知识点 2. Java 常见集合 3. 高并发编程(JUC 包) 4. JVM 内存管理 5. Java 8 知识点 6. 网络协议相关 7. 数据库相关 8. MVC 框架相关 9. 大数据相关 10. Linux 命令相关面试,
2021年度最全面JVM虚拟机,类加载过程与类加载器
前言类装载器子系统是JVM中非常重要的部分,是学习JVM绕不开的一关。一般来说,Java 类的虚拟机使用 Java 方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表
阿里程序员的Java之路!2021年最新Java面试点梳理
面试题模块介绍: 一、Java 基础 JDK 和 JRE 有什么区别? 和 equals 的区别是什么? 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? final 在 java 中有什么作用? java 中的 Math.round(1.5) 等于多少? String 属于基础的数据类型吗?