Java 多线程通信之多生产者/多消费者
2024-10-19 14:30:38
// 以生产和消费烤鸭为例
class Resource
{
private String name;
private int count = 1; // 记录烤鸭的编号
private boolean flag = false;
public synchronized void set(String name)
{
if(flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
flag = true;
this.notify();
}
public synchronized void out()
{
if(!flag)
try{this.wait();}catch(InterruptedException e){}
Sytem.out.println(Thread.currentThread().getName()+ "...消费者.."+ this.name);
flag = false;
this.notify();
}
}
class Producer implements Runnable
{
Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}
class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
class ProducerConsumerDemo
{
public static void main(String[] args)
{
// 创建资源
Resource r = new Resource();
// 创建任务
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
// 多生产者
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
// 多消费者
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
Thread t5 = new Thread(con);
// 开启线程
t0.start();
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
出现错误的两种情况:
- 线程安全问题(虚假唤醒): 线程1 生产的烤鸭被线程3 和线程5 两个线程同时消费
- if 只能判断标记一次, 会导致不该运行的线程运行了, 出现数据错误的情况
- while 可以多次判断标记, 解决了线程获取执行权后, 是否要运行的问题!
- 死锁
- notify() 一次只能唤醒一个线程, 如果本方唤醒类本方, 没有意义. 而且 while 判断标记多次,
会导致死锁. - notifyAll() 解决了本方线程一定会唤醒对方线程的问题.
- notify() 一次只能唤醒一个线程, 如果本方唤醒类本方, 没有意义. 而且 while 判断标记多次,
// 升级版代码
class Resource
{
private String name;
private int count = 1; // 记录烤鸭的编号
private boolean flag = false;
public synchronized void set(String name)
{
// 将 if 换为 while, 线程从冻结状态被唤醒后,需要判断 flag 标记之后, 确定是否继续生产"烤鸭"
while(flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
flag = true;
this.notifyAll(); // 肯定会唤醒对方的线程, 解决了死锁问题
}
public synchronized void out()
{
while(!flag)
try{this.wait();}catch(InterruptedException e){}
Sytem.out.println(Thread.currentThread().getName()+ "...消费者.."+ this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable
{
Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}
- [JavaSE 基础视频(毕向东)](https://www.bilibili.com/video/av3106510/#page=4)
最新文章
- 枚举扩展方法获取枚举Description
- JAVA中SERIALVERSIONUID的解释
- Confluent介绍(二)--confluent platform quickstart
- webservice和restful的区别
- tcpdump命令--实用篇
- UVa 232 Crossword Answers
- layout cannot be resolved or is not a field
- classloader.getresources() 介绍
- System.AccessViolationException: 尝试读取或写入受保护的内存 解决办法
- django note
- css学习笔记二
- android adb经常使用的命令
- [Oracle] 常用工具集之 - SQL*Loader
- android Android性能优化之如何避免Overdraw
- Java多线程Master-Worker模式
- FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)
- Hibernate的二级缓存策略
- 洛谷P4770 [NOI2018]你的名字 [后缀自动机,线段树合并]
- python学习之路07
- Python 3下Matplotlib画图中文显示乱码的解决方法