文章目录

  • 概述
  • jstack或者可视化工具检测是否死锁(没有)
  • 原因分析

概述

高并发编程-线程通信_使用wait和notify进行线程间的通信 - 遗留问题

我们看到了 应用卡住了 。。。。 怀疑是不是死锁呢? (其实没有)


jstack或者可视化工具检测是否死锁(没有)

C:\Users\Mr.Yang>E:E:\>cd E:\Program Files\Java\jdk1.8.0_161\binE:\Program Files\Java\jdk1.8.0_161\bin>jps
1504 MultiProduceConsumerDemoE:\Program Files\Java\jdk1.8.0_161\bin>jstack 1504
2019-10-01 00:44:23
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode):"DestroyJavaVM" #15 prio=5 os_prio=0 tid=0x0000000002983800 nid=0x3348 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Thread-3" #14 prio=5 os_prio=0 tid=0x0000000019fa5000 nid=0x3af0 in Object.wait() [0x000000001abff000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000078b682768> (a java.lang.Object)at java.lang.Object.wait(Object.java:502)at com.artisan.test.MultiProduceConsumerDemo.consume(MultiProduceConsumerDemo.java:42)- locked <0x000000078b682768> (a java.lang.Object)at com.artisan.test.MultiProduceConsumerDemo$2.run(MultiProduceConsumerDemo.java:63)"Thread-2" #13 prio=5 os_prio=0 tid=0x0000000019fa4000 nid=0x9e4 in Object.wait() [0x000000001aaff000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000078b682768> (a java.lang.Object)at java.lang.Object.wait(Object.java:502)at com.artisan.test.MultiProduceConsumerDemo.consume(MultiProduceConsumerDemo.java:42)- locked <0x000000078b682768> (a java.lang.Object)at com.artisan.test.MultiProduceConsumerDemo$2.run(MultiProduceConsumerDemo.java:63)"Thread-1" #12 prio=5 os_prio=0 tid=0x0000000019fa0000 nid=0x37cc in Object.wait() [0x000000001a9ff000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000078b682768> (a java.lang.Object)at java.lang.Object.wait(Object.java:502)at com.artisan.test.MultiProduceConsumerDemo.produce(MultiProduceConsumerDemo.java:20)- locked <0x000000078b682768> (a java.lang.Object)at com.artisan.test.MultiProduceConsumerDemo$1.run(MultiProduceConsumerDemo.java:55)"Thread-0" #11 prio=5 os_prio=0 tid=0x0000000019f9f800 nid=0x1bd4 in Object.wait() [0x000000001a8fe000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000078b682768> (a java.lang.Object)at java.lang.Object.wait(Object.java:502)at com.artisan.test.MultiProduceConsumerDemo.produce(MultiProduceConsumerDemo.java:20)- locked <0x000000078b682768> (a java.lang.Object)at com.artisan.test.MultiProduceConsumerDemo$1.run(MultiProduceConsumerDemo.java:55)"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000019d2f800 nid=0x3ba4 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C1 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x0000000019ca3800 nid=0x37e4 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x0000000019c54800 nid=0x2db0 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x0000000019c50800 nid=0x37bc waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x0000000019c2e000 nid=0x2ed4 runnable [0x000000001a2fe000]java.lang.Thread.State: RUNNABLEat java.net.SocketInputStream.socketRead0(Native Method)at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)at java.net.SocketInputStream.read(SocketInputStream.java:171)at java.net.SocketInputStream.read(SocketInputStream.java:141)at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)- locked <0x000000078b5dad50> (a java.io.InputStreamReader)at java.io.InputStreamReader.read(InputStreamReader.java:184)at java.io.BufferedReader.fill(BufferedReader.java:161)at java.io.BufferedReader.readLine(BufferedReader.java:324)- locked <0x000000078b5dad50> (a java.io.InputStreamReader)at java.io.BufferedReader.readLine(BufferedReader.java:389)at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000018860000 nid=0x34f8 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000019c08800 nid=0x1514 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001883a000 nid=0x22c in Object.wait() [0x0000000019b9e000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000078b408ec0> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)- locked <0x000000078b408ec0> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000002a73800 nid=0x29bc in Object.wait() [0x0000000019a9f000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000078b406b68> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)- locked <0x000000078b406b68> (a java.lang.ref.Reference$Lock)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)"VM Thread" os_prio=2 tid=0x0000000018818000 nid=0x381c runnable"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002998000 nid=0x3024 runnable"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x000000000299a000 nid=0x229c runnable"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000299b800 nid=0x2bbc runnable"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000299d000 nid=0x255c runnable"VM Periodic Task Thread" os_prio=2 tid=0x0000000019d67800 nid=0x1c5c waiting on conditionJNI global references: 334E:\Program Files\Java\jdk1.8.0_161\bin>

可以看到 并没有死锁的发生

或者 使用 jvisualvm 、 jmc 工具来看下都行

(jmc截图)

并且可以看到4个线程 均是 WAITING 状态

(jmc截图)


原因分析

为了方便观察,我们改造下,给线程起个名

package com.artisan.test;import java.util.stream.Stream;public class MultiProduceConsumerDemo {// 对象监视器-锁private final Object LOCK = new Object();// 是否生产出数据的标识private boolean isProduced = false;// volatile 确保可见性, 假设 i 就是生产者生产的数据private volatile int i = 0 ;public  void produce(){synchronized (LOCK){System.out.println(Thread.currentThread() + " GOT LOCK  " + isProduced);String msg = isProduced ? "已生产货物" : "没有货物可搬运";if (isProduced){try {System.out.println(Thread.currentThread() + " wait becauseof  " + msg );LOCK.wait();} catch (InterruptedException e) {e.printStackTrace();}}else{i++;System.out.println(Thread.currentThread() + " Produce:" + i);LOCK.notify();isProduced = true;}}}public void consume(){// 加锁synchronized (LOCK){System.out.println(Thread.currentThread() + " GOT LOCK " + isProduced);String msg = isProduced ? "已生产货物" : "没有货物可搬运";if (isProduced){System.out.println(Thread.currentThread() + " Consume:" + i);LOCK.notify();isProduced = false;}else{try {System.out.println(Thread.currentThread() + " wait becauseof  " + msg);LOCK.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {MultiProduceConsumerDemo produceConsumerDemo = new MultiProduceConsumerDemo();Stream.of("P1","P2").forEach(n-> new Thread(n){@Overridepublic void run() {while(true) produceConsumerDemo.produce();}}.start());Stream.of("C1","C2").forEach(n->new Thread(n){@Overridepublic void run() {while(true) produceConsumerDemo.consume();}}.start());}
}

运行下 ,可以看到程序并没有持续运行,而是假死了…

(每次运行的结果都有可能不一样,这里我们以这次的运行结果来分析下)

逐步分析下:

生产者的代码

消费者代码

  1. 线程P1锁,没有货物生产,isProduce=false
  2. 线程P1,生产货物 ,紧接着 LOCK.notify(); isProduced = true; ,其实第一步的LOCK.notify() 是没有什么作用的,因为没有任何线程wait. 执行完以后释放锁。 对应日志
  3. 紧接着,P1又抢到了锁,但是生产后没有被消费,所以直接进入LOCK.wati. 执行完以后释放锁。P1-----WAITING . 对应日志
  4. P2同上一步P1的操作 ,P2-----WAITING 对应日志
  5. C1 抢到资源 ,isProduce已经生产,所以C1线程直接消费,消费完成以后要通知生产者继续生产,即唤醒消费者 (LOCK.notify();),将isProduce标志位置为false . 执行完以后,释放锁。C1-----WAITING日志如下
  6. 紧接着C1又抢到了锁,因没有生产,所以进入LOCK.wait() ,释放锁。 对应日志
  7. 依次类推… 直到最后C2 唤醒了C1 ,此时C1看到isProduce=false, 则C1进入了wait ,这个时候4个线程都是watiing的状态了,就出现了4个线程均是wait状态,都不执行了,出现了假死 (因为notify方法,唤醒一个线程,具体是哪个线程是不确定的。)

那如何解决呢? 下篇博文我们一起来探讨下

高并发编程-线程通信_使用wait和notify进行线程间的通信2_多生产者多消费者导致程序假死原因分析相关推荐

  1. 高并发编程-线程通信_使用wait和notify进行线程间的通信

    文章目录 概述 场景 引子 synchronized wait/notify机制 synchronized wait/notify 改造 问题 概述 Java中线程通信协作的最常见的两种方式: syn ...

  2. 高并发编程-使用wait和notifyAll进行线程间的通信3_多线程下的生产者消费者模型和notifyAll

    文章目录 概述 解决办法 概述 高并发编程-线程通信_使用wait和notify进行线程间的通信2_多生产者多消费者导致程序假死原因分析 中分析了假死的原因,这里我们来看下改如何解决在多线程下出现的这 ...

  3. java线程高并发编程

    java线程详解及高并发编程庖丁解牛 线程概述: 祖宗: 说起java高并发编程,就不得不提起一位老先生Doug Lea,这位老先生可不得了,看看百度百科对他的评价,一点也不为过: 如果IT的历史,是 ...

  4. mysql导致带宽跑满_导致带宽跑满的原因分析

    用户们可能都有遇到过带宽跑满的状况,而可能导致带宽跑满的因素有很多方面,今天小编就来跟大家分析一下,可能导致带宽跑满的一些原因. 1.遭遇网络攻击 如果主机或者站点遭遇CC攻击或者DDoS攻击等,会在 ...

  5. libevent c++高并发网络编程_高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  6. 高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  7. 高并发编程_高并发编程系列:7大并发容器详解(附面试题和企业编程指南)...

    不知道从什么时候起,在Java编程中,经常听到Java集合类,同步容器.并发容器,高并发编程成为当下程序员需要去了解掌握的技术之一,那么他们有哪些具体分类,以及各自之间的区别和优劣呢? 只有把这些梳理 ...

  8. 高并发编程-自定义简易的线程池(2),体会原理

    文章目录 概述 示例 概述 高并发编程-自定义简易的线程池(1),体会原理 中只实现了任务队列,我们这里把其余的几个也补充进来 拒绝策略 关闭线程池 最小 最大 活动线程数 - 示例 比较简单,直接上 ...

  9. 高并发编程-Thread_正确关闭线程的三种方式

    文章目录 概述 stop() Deprecated 方式一 设置开关 方式二 调用interrupt API 方式三 暴力结束线程-> Daemon Thread + interrupt API ...

最新文章

  1. 什么叫点积的巧记理解
  2. Android之给图片去色,返回灰度图片以及ColorMatrix中setSaturation方法的用法
  3. AutoCAD 2013
  4. springboot脚本启动bat_SpringBoot系列(1)基础入门
  5. 菜鸟python_手把手教你,菜鸟也能用Python写一个2048游戏
  6. 利用BioPerl将DNA序列翻译成蛋白序列
  7. 网络安全法对计算机人员的影响,网络安全法的基本原则-网络安全论文-计算机论文.docx...
  8. 【转】细说@Html.ActionLink()的用法
  9. python安装包下载及安装(超详细)
  10. 安卓系统管理软件_便捷仓库管理软件智能管理系统
  11. Java、JSP房屋租赁管理系统
  12. 单片机C语言应用100例
  13. SetupFactory安装前卸载旧版本
  14. c语言实现万年历程序
  15. 2019软博会:和利时将展示在智能工厂等行业的解决方案
  16. 一次搞定亚马逊 Used Sold as New 二手品申诉,速度 Get!
  17. Java的“跨平台”特性
  18. git/svn reset/revert 回滚到服务器上的某一个版本
  19. CMake是什么?有什么用?
  20. 「力扣」第 546 题:移除盒子(很难的动态规划问题)

热门文章

  1. Linux环境下使用dosemu写汇编
  2. C++虚继承时的构造函数
  3. anaconda换源和恢复默认源
  4. sql join教程
  5. module 'itertools' has no attribute 'izip'
  6. scala外部传入时间参数-亲测有效
  7. 在有序旋转数组中找到最小值
  8. python库整理:heapq 最小堆
  9. 深度学习核心技术精讲100篇(八十)-脏数据如何处理?置信学习解决方案
  10. (纯干货)万字长文,数据分析利器 pandas 全教程