一件复杂的事,一个人如果不能做,两个人又做的不好,一群人就可能很好的解决了。对于线程来说也是,通过多个线程就能完成一个更复杂的功能,这就需要多个线程协作,协作就需要交流,但是交流总是会出问题的。在这篇文章中我们分析一下java多线程通信过程中出现的一个假死现象。然后给出一个解决办法。

一、假死现象重现

为了更好地演示我们的实例,我们使用生产者消费者模式,一边生产一边消费。

下面我们先试着实现一下。这个例子的功能描述如下:有一个产品a,生产方法生产a,消费方法消费a。然后10个生产线程生产,10个消费线程消费。永不停息。

上面的流程很清晰,一堆线程生产,生产了之后notify消费者去消费。

第一步:定义变量

public class ProduceAndConsumerModel {

//a表示共享变量 private int a = 0;

//lock就是一把锁 final private Object lock = new Object();

// isProduced表示是否已经生产的标志 private volatile boolean isProduced = false;

}

第二步:生产和消费方法(定义在上面的类中)

首先是生产方法

public void produce() throws InterruptedException {

synchronized (lock) {

// 如果已经生产了,那就等消费了再生产 if (isProduced) {

lock.wait();

} else {// 没有生产,那就生产一个,并通知消费者去消费 a++;

System.out.println("生产者" + Thread.currentThread().getName()

+ "生产一个产品:" + (a));

lock.notify();

isProduced = true;

}

}

}

然后是消费方法

public void consume() throws InterruptedException {

synchronized (lock) {

// 如果有产品,那就消费,并通知生产者可以继续生产了。 if (isProduced) {

System.out.println("消费者" + Thread.currentThread().getName()

+ "消费一个产品:" + (a));

lock.notify();

isProduced = false;

} else {// 如果没有产品,那就等待一会 lock.wait();

}

}

}

第三步:测试

public class ProduceAndConsumerModel {

public static void main(String[] args) {

ProduceAndConsumerModel model = new ProduceAndConsumerModel();

// 生产线程一直不停的生产 for (int i = 0; i < 10; i++) {

new Thread() {

public void run() {

while (true) {

model.produce();

}

};

}.start();

}

// 消费线程一直不停的消费 for (int i = 0; i < 10; i++) {

new Thread() {

public void run() {

while (true) {

model.consume();

}

};

}.start();

}

}

}

上面这个例子的功能,在一开始也已经说明了,这里produce和consume方法中,使用的是wait/notify机制来实现的,我们运行一下看会出现什么结果:

我们看到,本来整个程序是永不停歇的,但是在生产了6个产品之后,突然间就停歇了,也就是我们今天的主题,多线程通信出现了假死状态。为什么会出现这种现象呢?我们来分析一下原因。

二、假死状态分析

其实出现这个现象的原因很简单,那就是和我们的wait/notify机制有关,我们几句话来总结一下:

“假死”的现象就是全部线程都进入了WAITING状态(死锁),则程序就不再执行任何业务功能了,整个项目呈停止状态。上面的案例中出现假死的现象是由于仅仅唤醒了同类(生产者唤醒了生产者,消费者唤醒了消费者)的现象大量出现导致的。

下面我们画一张图来分析一下:

也就是说notify通知的是是同类。造成了这种堵塞现象。这是其根本原因,而且这张图是我们自己画的。下面我们就直接使用jstack工具来分析一下线程的状态。这两个工具是jdk自带的,我们可以直接使用。

第一步:使用jps查看当前电脑存在的所有java线程

第二步:使用jstack工具查看线程状态信息

现在我们知道了,目前所有的线程都是出于等待的状态,这也就是假死现象的验证。

假死现象的原因我们知道了,那么我们如何改正呢?

三、假死状态修复

假死现象的改正其实很简单,网上的方式也很多,比如说通过BlockingQueue或者是notifyAll方法。notifyAll方法超级简单,就是把上面produce和consume方法中的notify改成notifyAll方法即可。目的就是通知到所有的其他线程,生产线程该生产的生产,消费线程该消费的消费。

对于java多线程的系列的文章,这算是基础入门。还有更多文章我也经持续发布。感谢支持。OK,今天的文章先到这。

java程序假死_分析一个常见的java多线程通信问题(假死现象)相关推荐

  1. java 程序输出 赵_编写一个完整的JAVA的程序

    编写一个完整的JAVA的程序 关注:84  答案:1  mip版 解决时间 2021-02-05 08:43 提问者妳螚鬧俄螚笑 2021-02-05 02:59 1,接口Person Show()方 ...

  2. Linux给Java程序设置端口_扫描服务端口的Java程序

    在Linux下用C写了一个扫描指定IP地址对外开放端口号的程序.扫描自己的机器的端口号速度还是挺快的,用编写的程序扫描在美国的服务器时,等了10分钟,端口号才扫到1000左右.于是就想到了用多线程,可 ...

  3. java 开发 加固态_搭建一个完整的Java开发环境

    作为一个Java程序员,配置一个java开发环境是必备的技能,今天给广大菜鸟初学者补上一课.环境的配置,大概就分三个1,JDK 2,Tomcat(或者其他的)3,eclipse(或者myeclipse ...

  4. java写的家谱_创建一个家谱树java

    我有以下结构: Member { String firstName; String secondName; Member[] children; Member father; } >我必须在ja ...

  5. java中的复合数据类型是什么_【填空题】类是Java中的一种重要的复合数据类型,是组成Java程序的基本要素。一个类的实现包括两部分:____和_____....

    [填空题]类是Java中的一种重要的复合数据类型,是组成Java程序的基本要素.一个类的实现包括两部分:____和_____. 更多相关问题 [名词解释] 观叶树木 [单选] 开花时有浓郁香气的树种是 ...

  6. java程序样例_一个完整的java程序示例

    一个完整的java程序示例 2020-08-15 05:22 阅读数 74 第一个java程序 package mypack; //相当于一个目录 public class HelloWorld{ p ...

  7. 学java 开发会掉头_作为一个全新的开发人员,我会学到什么

    学java 开发会掉头 重点 (Top highlight) It's been five years since I learned to code and changed careers. 自从我 ...

  8. 程序员心中都有一个江湖,java世界,就是一个江湖!

    大千世界,无所不有.这世上不光有人类世界,还有咱们的 java 世界.今天就由我这个实习导游带领你们了解了解咱们的 java 世界的奇妙之处. 有一种暖男叫 catch,有一种真爱叫 try---ca ...

  9. 90 % Java 程序员被误导的一个性能优化策略

    转载自   90 % Java 程序员被误导的一个性能优化策略 我们经常看到一些 Java 性能优化的书或者理念,说不要在循环内定义变量,这样会占用过多的内存影响性能,而要在循环外面定义.接触 Jav ...

最新文章

  1. 路由器、路由与路由表
  2. 同时进科俩博士,一个被围着宠着、一个却被当成空气;凭什么?
  3. 如何检查电脑是否安装了python-python-如何检查安装了scikit的nltk版本?
  4. CSDN修改博客皮肤模板
  5. 一段话系列-领域模型是什么?
  6. Learning to rank基本算法小结
  7. E 做任务三(区间)
  8. webpack --- [读书笔记] webpack中常用的一些配置项
  9. 从零开始学习jQuery (九) jQuery工具函数 【转】
  10. Java字节码指令简介
  11. 最炫国漫《雾山五行》用 Python 了解一下到底有多优秀
  12. Ubuntu通过apt-get安装OpenCV
  13. 用SQL语句复制数据表
  14. 读书笔记 - 简约之美:软件设计之道
  15. oliver什么意思java_英语名字“oliver”是什么意思?
  16. 设置div显示隐藏的N种方法
  17. 执行scp命令自动输入密码的方法(expect方案)
  18. Spring Cloud入门系列(1)- Spring生态体系发展史+全系框架介绍
  19. Algorithm:图片隐藏术—基于加密算法实现图像隐术加密
  20. jQuery学习笔记(二)使用选择器一

热门文章

  1. 为了不被裁之NVMe-MI oob
  2. U盘图标改变与文件隐藏
  3. 微信公众号开发 糟糕的体验_糟糕的开发人员–好老板
  4. 如何查看网络计算机ip,怎么查ip地址 如何查看(局域网/互联网)本机ip地址
  5. hyperic hq笔记
  6. 【标签画像系列】标签体系建设方法论
  7. python英语词汇量测试_非常适合新手的一个Python爬虫项目: 打造一个英文词汇量测试脚本!...
  8. vue的:href和href
  9. 在SATA SSD + NVMe SSD双硬盘中安装ubuntu双系统
  10. 说说教育机构教学课程视频加密是如何实现的?