JAVA多线程之生产消费模型
2021/8/9 12:35:54
本文主要是介绍JAVA多线程之生产消费模型,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
生产消费模型
所谓生产消费模型,是通过一个容器来解决生产者和消费者的强耦合问题。通俗的讲,就是生产者不断的生产,
消费之也在不断消费,消费者消费的产品是生产者生产的,这就必然存在一个中间的容器,我们可以把这个容器
想象成一个仓库,当仓库没有满的时候,生产者生产产品,当仓库满了的时候,生产者不能继续生产产品,而需
处于等待状态。当仓库不为空的时候,消费者可以消费产品,当仓库为空的时候,消费者不能再消费产品,而应
处于等待状态。这样不断循环,在这个过程中,生产者和消费者是不直接杰出的,所谓的仓库其实就是一个阻塞
队列,生产者生产的产品不直接提供给消费者,而是提供给阻塞队列,这个阻塞队列就是来解决生产者和消费者
之间的强耦合,这就是生产者消费者模型。
wait()方法
1、注意wait()是Object里面的方法,而不是Thread里面的。它的作用是将当前线程置于预执行队列,并在wait()
所在的代码处停止,等待唤醒通知。
2、wait()只能在同步代码块或同步方法中执行,如果调用wait()方法,而没有持有适当的锁,就会抛出异常。
wait()方法调用后会释放出锁,线程与其他线程竞争重新获取锁。
3、线程调用了wait()方法后一直在等待,不会继续往下执行,wait()一旦执行,除非接受到唤醒操作或者异常
中断,否则不会往下执行
notify()方法
1、notify()方法也是要在同步代码块或者同步方法中调用的,它的作用是使停止的线程继续执行,调用notify()
方法后,会通知那些等待当前线程对象锁的线程,并使它们重新获取该线程的对象锁,如果等待线程比较多的时候,
则由线程规划器随机挑选出一个呈现wait状态的线程。
2、notify()调用之后不会立即释放锁,而是当执行notify()的线程执行完成,即退出同步代码块或同步方法时,
才会释放对象锁。
notifyAll()
唤醒所有处于等待状态的线程,一般使用notifyAll()比较多,因为notify随机唤醒一个线程,可能不是我们想要的
造成程序出现问题,notifyAll()唤醒所有等待线程则一定会得到我们想要的
例程
测试1,不加入同步和线程通信
Test类
package com.lding.test2; public class Test { public static void main(String[] args) { Queue queue=new Queue(); new Thread(new Producer(queue)).start(); new Thread(new Consumer(queue)).start(); } }
Queue类
package com.lding.test2; public class Queue { private int n; public int getN() { System.out.println("消费:"+n); return n; } public void setN(int n) { System.out.println("生产:"+n); this.n = n; } }
Producer类
package com.lding.test2; public class Producer implements Runnable{ Queue queue; Producer(Queue queue){ this.queue=queue; } @Override public void run() { int i=0; while (true){ queue.setN(i++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Consumer类
package com.lding.test2; public class Consumer implements Runnable{ Queue queue; Consumer(Queue queue){ this.queue=queue; } @Override public void run() { while (true){ queue.getN(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行结果
可以看到,0生产了一次却消费了两次。
测试2 加上同步
Queue类
package com.lding.test2; public class Queue { private int n; public synchronized int getN() { System.out.println("消费:"+n); return n; } public synchronized void setN(int n) { System.out.println("生产:"+n); this.n = n; } }
生产了18并没有消费
生产了22消费了两次22
版本3 加上线程之间的通信
Queue类
package com.lding.test2; public class Queue { private int n; boolean flag=false;//flag=false 容器中无数据, flag=true 容器中有商品 public synchronized int getN() { if(!flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消费:"+n); flag=false;//消费完毕 容器没数据 notifyAll(); return n; } public synchronized void setN(int n) { if(flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产:"+n); this.n = n; flag=true;//生产完毕 容器中有数据 notifyAll(); } }
运行结果完全是生产一个,消费一个,不会出现生产一次消费两次或者生产完不消费的情况。
这篇关于JAVA多线程之生产消费模型的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器
- 2024-11-26Java云原生资料:新手入门教程与实战指南
- 2024-11-26JAVA云原生资料入门教程
- 2024-11-26Mybatis官方生成器资料详解与应用教程
- 2024-11-26Mybatis一级缓存资料详解与实战教程
- 2024-11-26Mybatis一级缓存资料详解:新手快速入门
- 2024-11-26SpringBoot3+JDK17搭建后端资料详尽教程