当前位置: 首页 > news >正文

【多线程案例】生产者消费者模型(堵塞队列)

文章目录

    • 1. 什么是堵塞队列?
    • 2. 堵塞队列的方法
    • 3. 生产者消费者模型
    • 4. 自己实现堵塞队列

1. 什么是堵塞队列?

堵塞队列也是队列,故遵循先进先出的原则。但堵塞队列是一种线程安全的数据结构,可以避免线程安全问题,当队列为空时,继续出队列会发生堵塞,直至其他线程有元素进队列。当队列满时,继续入队列会堵塞,直至其他线程有元素出队列。
生产者消费者模型就是最经典的堵塞队列模型之一。

2. 堵塞队列的方法

Java标准库里含有堵塞队列,我们使用时可以直接使用标准库即可。

  • BlockingQueue是个接口,真正实现的类是:LinkedBlockingQueue。
  • put方法入队列,take方法出队列,具有堵塞性。
  • peek,offer,poll等方法也可以使用,但是不具有堵塞性。
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
queue.put();
queue.take();

3. 生产者消费者模型

这是一个常见的并发编程模型,用于协调生产者和消费者之间的工作,在这个模型中,一个线程负责生产元素,一个线程负责消费元素。
它也是一个堵塞队列 ,所以具有堵塞队列的特性。

public class Test {public static void main(String[] args) {BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();//t1线程负责生产元素Thread t1 = new Thread(() -> {try{Random random = new Random();while (true){int i = random.nextInt();System.out.println("生产元素: " + i);queue.put(i);Thread.sleep(1000);}}catch (InterruptedException e){e.printStackTrace();}});//t2负责消费元素Thread t2 = new Thread(() -> {try {while(true){int i = queue.take();System.out.println("消费元素: " + i);}} catch (InterruptedException e) {e.printStackTrace();}});t1.start();t2.start();}
}

运行结果:
1

4. 自己实现堵塞队列

自己实现堵塞队列需要满足:

  • 通过循环队列来实现;
  • 使用synchronized实现加锁,进行同步;
  • put 插入元素的时候, 判定如果队列满了, 就进行 wait. (注意, 要在循环中进行 wait. 被唤醒时不一定队列就不满了, 因为同时可能是唤醒了多个线程);
  • take 取出元素的时候, 判定如果队列为空, 就进行 wait. (也是循环 wait) ;
class BlockingQueue{//定义一个数组private int[] arr;//数组中元素个数private int size = 0;//记录数组头的位置private int read = 0;//记录尾的位置private int tail = 0;//锁Object lock = new Object();//构造方法,确定数组大小public BlockingQueue(int i){arr = new int[i];}//入队列public void put(int value){try{//加锁,保证线程安全synchronized (lock){//使用while,不要使用if,否则notifyAll时,所有等待线程都被唤醒,造成线程安全while(arr.length == size){lock.wait();}arr[tail] = value;//循环队列tail = (tail + 1) % arr.length;//添加一个元素,size加一次size++;//唤醒所有线程lock.notifyAll();}}catch (InterruptedException e){e.printStackTrace();}}public int take() {//返回值,不能写在try里面int value = 0;try {//上锁synchronized (lock) {//队列为0,等待,使用whilewhile (size == 0) {lock.wait();}//赋返回值value = arr[read];//循环read = (read + 1) % arr.length;//出队列一个,减一个size--;//唤醒lock.notifyAll();}} catch (InterruptedException e) {e.printStackTrace();}//返回值return value;}}
public class Test4 {public static void main(String[] args) throws InterruptedException {BlockingQueue queue = new BlockingQueue(10);Thread t1 = new Thread(() -> {try{Random random = new Random();while (true){int value = random.nextInt(100);System.out.println("生产元素: " + value);queue.put(value);Thread.sleep(100);}}catch (InterruptedException e){e.printStackTrace();}});//t2负责消费元素Thread t2 = new Thread(() -> {while(true){int value = queue.take();System.out.println("消费元素: " + value);}});t1.start();Thread.sleep(2000);t2.start();}
}

1111
1 因为t2 未启动,所以只能生产元素,当生产10个元素后,队列满了,进入堵塞,等待被唤醒;
2 因为t1生产时,每次都会休眠,线程执行非常迅速,所以队列一直出元素,直到队列为空,进入堵塞,等待被唤醒;
3生产一个元素消费一个元素。

http://www.lryc.cn/news/152703.html

相关文章:

  • 数据结构与算法基础-学习-30-插入排序之直接插入排序、二分插入排序、希尔排序
  • Qt+C++桌面计算器源码
  • kubesphere安装Maven+JDK17 流水线打包
  • 百度搜索清理大量低质量网站
  • WPF数据模板
  • 浙江绿农环境:将废弃矿山变耕地,为生态文明贡献力量
  • HTML/CSS盒子模型
  • 《Java面向对象程序设计》学习笔记——CSV文件的读写与处理
  • opencv 案例05-基于二值图像分析(简单缺陷检测)
  • Elasticsearch入门介绍
  • QML Book 学习基础3(动画)
  • Lesson4-3:OpenCV图像特征提取与描述---SIFT/SURF算法
  • 语言基础篇9——Python流程控制
  • MATLAB算法实战应用案例精讲-【概念篇】构建数据指标方法(补充篇)
  • 【pyqt5界面化工具开发-12】QtDesigner图形化界面设计
  • CXL.mem S2M Message 释义
  • 设计模式—外观模式(Facade)
  • Stack Overflow开发者调查发布:AI将如何协助DevOps
  • 去掉鼠标系列之二:Sublime Text快捷键使用指南
  • docker-compose安装node-exporter, prometheus, grafana
  • 企业架构LNMP学习笔记10
  • [国产MCU]-W801开发实例-I2C控制器
  • 植物根系基因组与数据分析
  • 2.3 数据模型
  • RT-Thread 中断管理学习(一)
  • 学习周报9.3
  • win10 查看指定进程名的端口号
  • 函数的递归调用
  • 李宏毅机器学习笔记:RNN循环神经网络
  • 基于JavaWeb和mysql实现校园订餐前后台管理系统(源码+数据库)