多线程使用wait和notify做生产者消费者模型导致线程全部假死
时间:2022-04-29
本文章向大家介绍多线程使用wait和notify做生产者消费者模型导致线程全部假死,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
分析假死的原因:
首先我们每次只生产一个数据,然后消费者进行消费,
public class Value {
public static String value = "";//这个值作为生产消费的容器
}
生产者端代码:
private String lock;
public Producer (String lock) {
super();
this.lock = lock;
}
public void setValue() {
try {
synchronized (lock) {
while (!"".equals(Value.value)) {
System.out.println("生產者:"+Thread.currentThread().getName()+"等待");
lock.wait();
}
System.out.println("生產者:"+Thread.currentThread().getName()+"开始工作了");
String value = "Producer";
System.out.println("set value :"+value);
Value.value = value;
lock.notify();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
消费者端
private String lock;
public Consumer(String lock) {
this.lock = lock;
}
public void getValue() {
try {
synchronized (lock) {
if ("".equals(Value.value)) {
System.out.println("消费者:"+Thread.currentThread().getName()+"等待");
lock.wait();
}
System.out.println("消费者:"+Thread.currentThread().getName()+"开始消费了");
System.out.println("get value :"+Value.value );
Value.value = "";
lock.notify();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public class MyThread1 extends Thread {
private Producer p;
public MyThread1(Producer p) {
this.p = p;
}
@Override
public void run() {
while(true){
p.setValue();//此线程不停的生产
}
}
package com.demo.thread;
public class MyThread2 extends Thread{
private Consumer c;
public MyThread2(Consumer c) {
this.c = c;
}
@Override
public void run() {
while (true) {
c.getValue();//此线程不听的消费
}
}
}
测试:
String lock = new String("lock");
Producer p = new Producer (lock);
Consumer c = new Consumer (lock);
MyThread1[] t1 = new MyThread1[2];
MyThread2 [] t2 = new MyThread2[2];
for(int i = 0 ;i<2;i++){
t1[i] = new MyThread1(p);
t1[i].setName("生产者:"+(i+1));
t2[i] = new MyThread2(c);
t2[i].setName("消费者:"+(i+1));
t1[i].start();
t2[i].start();
}
Thread.sleep(3000);
Thread[] tArr = new Thread [Thread.currentThread().getThreadGroup().activeCount()];
Thread.currentThread().getThreadGroup().enumerate(tArr);
for(int i = 0 ;i<tArr.length;i++){
System.out.println(tArr[i].getName()+"t"+tArr[i].getState());
}
截取控制台代码部分代码: 分析:因为notify每次只唤醒一个线程,因此并不确定他唤醒的是哪一个线程,所以消费1唤醒的是消费者2,此时刚好没有数据被生产,消费者2也进入等待,并唤醒生产者2,生产者2生产完数据之后进入wait同时唤醒线程,此时唤醒的是生产者1 ,因为数据不为空,因此两生产者都进入等待状态,此时四个线程全部wait,即假死状态,结果如控制台所示. 解决方式:这里每次执行完毕之后应该唤醒所有线程即可.
生產者:生产者:2开始工作了
set value :Producer
消费者:消费者:1开始消费了
get value :Producer
消费者:消费者:1等待
生產者:生产者:2开始工作了
set value :Producer
生產者:生产者:2等待
生產者:生产者:1等待
消费者:消费者:2开始消费了
get value :Producer
消费者:消费者:2等待
生產者:生产者:2开始工作了
set value :Producer
生產者:生产者:2等待
生產者:生产者:1等待
消费者:消费者:1开始消费了
get value :Producer
消费者:消费者:1等待//消费者1等待,唤醒消费者2
消费者:消费者:2开始消费了
get value :
消费者:消费者:2等待//消费者2唤醒生产者2
生產者:生产者:2开始工作了
set value :Producer
生產者:生产者:2等待//从这里开始,生产者2唤醒1,两者最后都进入wait.
生產者:生产者:1等待
main RUNNABLE
生产者:1 WAITING
消费者:1 WAITING
生产者:2 WAITING
消费者:2 WAITING
- Spring Cloud(二)Consul 服务治理实现
- Spring Cloud(一)服务的注册与发现(Eureka)
- Shard 分片集群
- 面试官最爱的volatile关键字
- 玩转 WebView ,突破系统限制,让缓存更简单,更灵活
- Mycat 读写分离 数据库分库分表 中间件 安装部署,及简单使用
- 50道Java线程题
- Jrebel6.3.3破解,配置图文教程
- Spring Cloud(十一)高可用的分布式配置中心 Spring Cloud Bus 消息总线集成(RabbitMQ)
- Keras中带LSTM的多变量时间序列预测
- Spring Cloud(十)高可用的分布式配置中心 Spring Cloud Config 中使用 Refresh
- Hibernate 的性能优化的时候碰到了"抓取策略",有四种
- 基于 Spring Cloud 完整的微服务架构实战
- maven build时报错Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ELK-elasticsearch-6.3.2部署
- Real World CTF 2018 bookhub 总结
- python http.server open redirect vulnerability
- ELK-elasticsearch-6.3.2插件【head,bigdesk,cerebro[kopf]】安装
- ELK-kibana-6.3.2部署
- node.js + postgres 从注入到Getshell
- ELK-logstash-6.3.2部署
- K8S节点异常怎么办?TKE"节点健康检查和自愈"来帮忙
- ELK-logstash-6.3.2-常用配置
- ELK-elkstack-使用消息队列
- kafka_2.11-2.0.0_安装部署
- 谈escapeshellarg绕过与参数注入漏洞
- Django debug page XSS漏洞(CVE-2017-12794)分析
- kafka_2.11-2.0.0_常用操作
- shell脚本:通过域名获取证书的过期时间