随笔 - 303  文章 - 0  评论 - 3  阅读 - 15万

Java线程间通讯——等待通知机制

  在JDK中实现线程同步等待闭环(FutureTask/Future)中已经实现了线程之间的同步等待。具体如何实现的呢?需要分析具体方式具体代码,如下:

  1、join()方法

            

  2、Future/FutureTask

            

  以上两图中都有wait字眼,即等待线程结束。这种Java中对多线程执行顺序使用等待/通知控制的方式也称为阻塞/唤醒机制:是指一个线A用了Owait()方法入等待状,而另一个线B调用了Onotify()或者notifyAll()方法,线A收到通知后从Owait()方法返回,而执行后操作。上述两个线程通过对O来完成交互,而象上的wait()notify/notifyAll()关系就如同开关信号一,用来完成等待方和通知方之的交互工作。

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

  以上同步等待过程中线程之如何通信的呢?这里的通信是指线程之以何种机制来交信息。在共享内存的并模型里,线程之共享程序的公共状态(在JVM运行时内存管理之线程共享详细介绍了线程共享内存,通-内存中的公共状态进式通信。

  Java的并发选择采用的就是共享内存模型JMM,即隐式通讯显式同步(如上图两种方式的同步等待方式)。

            

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

  先通过单线程(生产者和消费者)使用该机制实践,从结果看:先生产后消费不会出现没有生产就消费的情况。具体代码和测试结果如下:

  产品流水线(自定义队列):

            

  生产者:

            

  消费者:

            

            

            

  再看多线程(生产者和消费者分别多线程):

            

             

   再执行一次:

            

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

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

            

  消费者线程从下标0开始获取消息队列中的数据,下标(getIndex)增加自加1(如果下标等于队列长度,则下标从0重新开始);同时队列长度(size)减1,如果消息队列长度为0时wait()——等待生产者。生产者线程数据状态正好与之相反。

  size作为线程共享数据放在元数据区,任意线程的get或put方法都可以随机时间sleep之后对其进行修改。失控的点就在此处:当size小于等于0时,并没有有效阻塞消费者进行数据的获取——因为第一次阻塞成功以后就直接进行了相关的操作,而多线程中每次操作前都得进行阻塞、等待、通知的操作。

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

            

  与单线程对比:

            

  get方法做类似的调整——代码基本没有变化,只是利用递归及非你即我的增强了抢对象锁的逻辑。

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

    等待方遵循如下原则:

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

          逻辑

        }

    通知方遵循如下原则:

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

   

 

posted on   池塘里洗澡的鸭子  阅读(184)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示