在并发编程中,实际处理涉及两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。

  通信是指线程之间以何种机制来交换信息。在共享内存的并发模型里,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。

  同步是指程序中用于控制不同线程间操作发生相对顺序的机制。在共享内存并发模型里,同步是显式进行的。开发人员必须显示指定某个方法或某段代码需要在线程之间互斥执行。

 Java的并发选择采用的就是共享内存模型JMM,即隐式通讯显式同步。

    

  在如何在两个线程之间共享数据 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中通过案例浅析了Java线程之间如何实现共享数据的两种方式,同时通过测试结果也可以知道线程之间的执行相对顺序是随机的,需要开发人员进行有效的同步控制。Java中对多线程执行顺序控制利用等待/通知也称为阻塞/唤醒机制实现。

  等待/通知的相关方法是任意Java对象都具备的,因为这些方法被定义在所有对象的超类java.lang.Object上:
    

  等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()和notify/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。

  先看单线程使用该机制:通过实践结果看,生成一个消费一个。

  

  再看多线程:

    

  再执行一次:

    

  多线程每次执行的结果似乎都不一样,也不是先生产后消费。wait和notify在此多线程应用不失效了?!从通知等待机制来分析,多线程的案例中6个线程分两组分别调用了对象myQueue中的wait()和notify(),相互通讯不应该出现失效的情况,为什么还是会出现消费者线程没有等到生产者的通知已生产完毕再进行消费的情况?

  分析源代码,通知等待机制哪里失控了?首先分析消费者线程:

    

  从源码看:消费者线程根据随机数获取消息队列中的数据。同时消息队列长度为0时wait(),除此以外都是根据随机数取数据。失控的点就在此处:如果消息队列长度不为0,比如说其长度为2,同时随机数为3,那么消费者线程取队列中的第4个数据——可想而知是没有任何元素在此处的。

  综合上述,多线程并发如果只是有关键字synchronized,wait(),notify()等方法并不能完全保证业务逻辑的正确性即有效同步。怎么解决这个问题呢?还需要合理的业务逻辑:

    

  以上可以得出一个小经验:提炼出等待/通知的经典范式——加锁,循环和处理逻辑,该范式分为两部分,分别针对等待方(消费者)和通知方(生产者)。

    等待方遵循如下原则:

      1)获取对象的锁。
      2)如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件。
      3)条件满足则执行对应的逻辑。
      对应的伪代码如下:
        synchronized(对象) {
          while(条件不满足) {
            对象.wait();
          }

          对应的处理逻辑

        }

    通知方遵循如下原则:

      1)获得对象的锁。
      2)改变条件。
      3)通知所有等待在对象上的线程。
      对应的伪代码如下:
        synchronized(对象) {
          改变条件
          对象.notifyAll();
        }

   

JMM之Java线程间通讯——等待通知机制及其经典范式的更多相关文章

  1. Java 线程间通信 —— 等待 / 通知机制

    本文部分摘自<Java 并发编程的艺术> volatile 和 synchronize 关键字 每个处于运行状态的线程,如果仅仅是孤立地运行,那么它产生的作用很小,如果多个线程能够相互配合 ...

  2. Java 线程间通讯(共享变量方式)

    Java线程间通讯,最常用的方式便是共享变量方式,多个线程共享一个静态变量就可以实现在线程间通讯,但是这需要注意的就是线程同步问题. 一.没考虑线程同步: package com.wyf; publi ...

  3. Java Concurrency - wait & notify, 等待通知机制

    生产者消费者问题是一个常见的多线程同步案例:一组生产者线程和一组消费者线程共享一个初始状态为空.大小为 N 的缓冲区.只有当缓冲区没满的时候,生产者才能把消息放入缓冲区,否则必须等待:只有缓冲区不空的 ...

  4. Java并发读书笔记:线程通信之等待通知机制

    目录 synchronized 与 volatile 等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 在并发编程中,保证线程同步,从而实现线程之 ...

  5. Java 线程间通讯

    /* 线程间通讯: 多个线程在处理同一资源,但是任务却不同. */ package com.cwcec.test; class Input implements Runnable { Resource ...

  6. java多线程系列(三)---等待通知机制

    等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...

  7. Java 线程间通讯(管道流方式)

    一.管道流是JAVA中线程通讯的常用方式之一,基本流程如下: 1)创建管道输出流PipedOutputStream pos和管道输入流PipedInputStream pis 2)将pos和pis匹配 ...

  8. Java并发编程,Condition的await和signal等待通知机制

    Condition简介 Object类是Java中所有类的父类, 在线程间实现通信的往往会应用到Object的几个方法: wait(),wait(long timeout),wait(long tim ...

  9. 12.详解Condition的await和signal等待通知机制

    1.Condition简介 任何一个java对象都天然继承于Object类,在线程间实现通信的往往会应用到Object的几个方法,比如wait(),wait(long timeout),wait(lo ...

随机推荐

  1. axios发送两次请求问题解决

    在使用axios的过程中,会发送两次请求. 看了下是因为有一个请求是OPTIONS来判断跨域的时候让不让发送请求的. 这个不算是一个bug,但是发送两个请求着实让人看着不舒服.于是修改了下,原来的请求 ...

  2. EgLine V0.3—LVGL官方拖拽式UI编辑工具(可导出代码)

    ** EdgeLine ** 是LVGL官方团队退出的一款拖拽式UI编辑工具,现在还处于测试间断,目前最新版本为v0.3,已经可导出代码. 注意: 使用该软件需要注册lvgl账号,这一步可能需要代理 ...

  3. HDU 1106 (1.3.5) 排序 (C语言描述)

    排序 Problem Description 输入一行数字,如果我们把这行数字中的'5'都看成空格,那么就得到一行用空格分割的若干非负整数(可能有些整数以'0'开头,这些头部的'0'应该被忽略掉,除非 ...

  4. 【Java】多态性

    文章目录 多态性 向下转型 多态性 可以理解为一个事物的多种形态. 对象的多态性:父类的引用指向子类的对象.只适用于方法,不适用于属性(编译和运行都看左边) 总结:对于对象的多态性,编译,看左边:运行 ...

  5. 【机器学习】svm

    机器学习算法--SVM 目录 机器学习算法--SVM 1. 背景 2. SVM推导 2.1 几何间隔和函数间隔 2.2 SVM原问题 2.3 SVM对偶问题 2.4 SMO算法 2.4.1 更新公式 ...

  6. 保存网页到zotero研究

    打印长页 打印长页很麻烦,打印加载时间过长,打印后无法选取文字 https://www.zhihu.com/question/52639201?sort=created 插件 浏览器自带直接网页打印p ...

  7. CMake语法—内置变量

    目录 CMake语法-内置变量 1 CMake变量分类 1.1 普通变量 1.2 缓存变量 1.3 环境变量 1.4 内置变量 2 CMake内置变量分类 2.1 提供信息的变量 2.2 改变行为的变 ...

  8. python os模块 文件操作

    Python内置的os模块可以通过调用操作系统提供的接口函数来对文件和目录进行操作 os模块的基本功能: >>> import os >>> os.name 'po ...

  9. log4j学习记录以及相关配置(精简版)

    使用log4j时关键配置 log4j的maven依赖 <dependency> <groupId>log4j</groupId> <artifactId> ...

  10. 1.Flink实时项目前期准备

    1.日志生成项目 日志生成机器:hadoop101 jar包:mock-log-0.0.1-SNAPSHOT.jar gmall_mock ​ |----mock_common ​ |----mock ...