【JavaSE】多线程案例---阻塞队列

1. 阻塞队列

阻塞队列是一种特殊的队列,也遵守 " 先进先出 " 的原则。

阻塞队列是一种线程安全的数据结构,并且具有以下特性:

1. 当队列为满时,继续进行入队列操作就会阻塞,直到有其他线程从队列中取走元素

2. 当队列为空时,继续进行出队列操作就会阻塞,直到有其他线程往队列中插入元素

阻塞队列的一个典型应用场景就是”生产者消费者模型“ 。

1.1 生产者消费者模型 

在多线程编程中,生产者消费者模型是一种典型的编码技巧,生产者消费者模型通过阻塞队列来解决生产者和消费者强耦合的问题。

在生产者消费者模型中,生产者不与消费者直接进行通讯,而是通过阻塞队列来间接的进行通讯。当生产者产出一个数据后,它不会等待消费者来处理,而是将产出的数据扔到阻塞队列中,等到消费者去处理数据时,消费者也不会直接跟生产者去要数据,而是从阻塞队列中获取需要处理的数据。

如下图

在生产者消费者模型中引入阻塞队列有什么影响呢?

1 .解耦合

      我们假设有两个服务器,分别为A服务器和B服务器,当A服务器和B服务器直接进行交流时,编写A服务器的代码时,多多少少也会涉及到一点B服务器的逻辑,编写B服务器的代码时多多少少也会涉及到一些A服务器的逻辑,这样就导致了两个服务器的代码就有了强耦合性。而当我们引入阻塞队列之后,就会变成A服务器与阻塞队列进行交涉,B服务器和阻塞队列进行交涉,从而间接完成A服务器和B服务器的间接交涉,这样A服务器和B服务器就不会直接进行交涉了。此时,A服务器中的代码中就看不到B服务器了,B服务器中的代码中就看不到A服务器了。这样就降低了代码大的耦合性。

2.削峰填谷

    服务器接收的数据量可以理解为一个波形图,当A服务器短时间内接收的数据量达到一个峰值时,很容易将A服务器搞挂,此时如果将这些大量的数据直接交给服务器来处理,B服务器也很可能挂掉。但是,如果有了一个阻塞队列,当数据的发送达到一个峰值时,A服务器可以将数据放到阻塞队列中,防止A服务器挂掉。当数据大的发送量达到一个波谷时,B服务器就可以利用数据的传送处于波谷的时间去处理阻塞队列中的数据,从而防止B服务器因为一股脑处理大量数据而挂掉。

1.2 标准库中的阻塞队列 

 在Java标准库中内置了一个阻塞队列,如果我们需要在一些程序中使用阻塞队列,使用标准库提供的即可

1. Java标准库提供的标准库是一个名为BlockingQueue的接口,真正实现的类是LinkedBlockingQueue 

2. put方法用于阻塞式的入队列,take方法用于阻塞式的出队列

3. BlockingQueue也有offer,poll,peek等方法,但是这些方法没有阻塞性

1.3 用标准库的阻塞队列实现一个生产者消费者模型

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;public class Demo26 {public static void main(String[] args) throws InterruptedException {BlockingQueue<Integer> blockingQueue=new LinkedBlockingQueue<>(100);Thread producer=new Thread(()->{try{int id=0;for(int i=0;i<100;i++){Thread.sleep(1000);blockingQueue.put(id);System.out.println("producer生产数据:"+id);id++;}}catch (InterruptedException e){e.printStackTrace();}},"producer");Thread consumer=new Thread(()->{try{for (int i = 0; i < 100; i++) {Thread.sleep(1000);int take=blockingQueue.take();System.out.println("consumer消费数据:"+take);}}catch (InterruptedException e){e.printStackTrace();}},"consumer");producer.start();consumer.start();producer.join();consumer.join();}
}

2.模拟实现一个阻塞队列

实现思路:

1.由于阻塞队列要不断有数据入队列和出队列,我们呢可以使用循环队列来实现

2.组要模拟实现put方法和take方法

3.在put过程中,发现队列满了或者在take过程中,发现队列为空,我们就要wait

4.注意wait要搭配一个循环来使用,因为wait也有可能被Interrupt这样的方法唤醒

5.使用syncronized进行加锁控制

代码实现:

class MySubBLockingQueue{private volatile int[] data=null;private volatile int head=0;private volatile int tail=0;private volatile int size=0;public MySubBLockingQueue(int capacity){data=new int[capacity];}public void put(int number) throws InterruptedException {synchronized (this){//判断队列是否满了while (size==data.length){this.wait();}data[tail]=number;tail++;size++;if(tail>=data.length){tail=0;}this.notify();//tail=(tail+1)%data.length;}}public int take() throws InterruptedException {int back=0;synchronized (this){//判断队列是否为空while (size==0){this.wait();}back=data[head];head++;size--;if(head>= data.length){head=0;}//head=(head+1)%data.length;this.notify();}return back;}
}

 

3.用模拟实现的阻塞队列实现生产者消费者模型

class MySubBLockingQueue{private volatile int[] data=null;private volatile int head=0;private volatile int tail=0;private volatile int size=0;public MySubBLockingQueue(int capacity){data=new int[capacity];}public void put(int number) throws InterruptedException {synchronized (this){//判断队列是否满了while (size==data.length){this.wait();}data[tail]=number;tail++;size++;if(tail>=data.length){tail=0;}this.notify();//tail=(tail+1)%data.length;}}public int take() throws InterruptedException {int back=0;synchronized (this){//判断队列是否为空while (size==0){this.wait();}back=data[head];head++;size--;if(head>= data.length){head=0;}//head=(head+1)%data.length;this.notify();}return back;}
}
public class Demo27 {public static void main(String[] args) throws InterruptedException {MySubBLockingQueue bLockingQueue=new MySubBLockingQueue(100);Thread producer=new Thread(()->{try{int id=0;for (int i = 0; i < 100; i++) {Thread.sleep(1000);bLockingQueue.put(id);System.out.println("producer生产数据:"+id);id++;}}catch (InterruptedException e){e.printStackTrace();}},"producer");Thread consumer=new Thread(()->{try{for (int i = 0; i < 100; i++) {Thread.sleep(1000);int take=bLockingQueue.take();System.out.println("consumer消费数据:"+take);}}catch (InterruptedException e){e.printStackTrace();}},"consumer");producer.start();consumer.start();producer.join();consumer.join();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/13253.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

SQL练习(2)

题源&#xff1a;牛客官网 选择题 假设创建新用户nkw&#xff0c;现在想对于任何IP的连接&#xff0c;仅拥有user数据库里面的select和insert权限&#xff0c;则列表语句中能够实现这一要求的语句是&#xff08;&#xff09; A grant select ,insert on *.* to nkw% B grant…

Hyper-v中ubuntu与windows文件共享

Hyper-v中ubuntu与windows文件共享 前言相关链接第一步--第一个链接第二步--第二个链接测试与验证 前言 关于Hyper-V的共享我搞了好久&#xff0c;网上的很多教程太过冗余&#xff0c;我直接采用最简单的办法吧 相关链接 Hyper-V中Ubuntu 同windows系统共享文件夹-百度经验 …

【TCP零窗口问题】

零窗口问题说明 零窗口问题(Zero Window Problem)是指在TCP连接中,当接收方的接收缓冲区已满时,无法接受新的数据。此时,接收方会向发送方发送一个窗口大小为0的TCP消息,告知其暂停发送数据,直到接收方释放出缓冲区空间。这种情况在高负载或接收方处理能力不足时比较常见…

Oracle OCP认证考试考点详解082系列19

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 91. 第91题&#xff1a; 题目 解析及答案&#xff1a; 关于 Oracle 数据库中的索引及其管理&#xff0c;以下哪三个陈述是正确的&#x…

2445.学习周刊-2024年45周

一片树叶展示了秋天的美 ✍优秀博文 数据仓库如何划分主题域在忙碌的工作中如何保持信息的输入&#xff1f;PC小米妙享安装解锁流转补丁智能数据建设与治理Dataphin对方讲话不要乱插嘴轩师处世之道 ✍实用工具 typing-practice云搭 自动化巡检系统 ✍精彩言论 话说的越快、…

关于解决使用VMWare内的虚拟机无法识别USB问题小结

目录 前言 0. 查看是不是没有开启USB3.0的支持 1. 检查一下是否禁用了VMWare USB服务 2. 无奈之举 前言 笔者今天帮助一位同志解决了VMWare内的虚拟机不识别挂载设备的办法。这里对笔者使用的排查手段做一个总结。 0. 查看是不是没有开启USB3.0的支持 我们的第一件事情就…

【364】基于springboot的高校科研信息管理系统

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古…

RN codegen编译报错

react-native codegen 编译报错 error: redefinition of ‘NativeAccessibilityInfoSpecJSI’ class JSI_EXPORT NativeAccessibilityInfoSpecJSI : public JavaTurboModule 解决&#xff1a; codegen不能和项目本身一起编译&#xff0c;先执行./gradlew clean&#xff0c;然…

大数据技术之Hadoop :我是恁爹

就如上图中的技术分类&#xff0c;大数据技术主要解决的就是海量数据的存储和计算问题。 这两个问题的解决方案最先被 Google 被提出&#xff0c;用于解决 Google 搜索引擎海量的网页存储和索引的构建。对应的技术就是日后被人所熟知的 HDFS 和 MapReduce。 不关注大数据的可…

ATAT-mcsqs生成准随机结构(SQS)更新

通常使用第一性原理计算某些多元素占据原胞中同一位置的结构会优先考虑使用准随机结构&#xff08;special quasirandom structure&#xff0c;SQS&#xff09;来进行模拟建模。此篇教程意在整理一个较为简便的操作流程&#xff0c;以供参考。 合金理论自动化工具包(ATAT)1是一…

人际交往中,想要有好人缘,需做到“三要”,做到一个,也是好事

人际交往中&#xff0c;想要有好人缘&#xff0c;需做到“三要”&#xff0c;做到一个&#xff0c;也是好事 在这个世上&#xff0c;每个人都是一座孤岛&#xff0c;但通过人际交往这座桥梁&#xff0c;我们能够彼此相连&#xff0c;共同编织出一张温暖的社会网络。 好人缘&a…

政务数据治理专栏开搞!

写在前面 忙忙碌碌干了一年政务数据治理的工作&#xff0c;从法人数据到自然人&#xff0c;从交通到地理信息等等&#xff0c;突发想法开一个专栏讲一讲政务数据遇到的问题&#xff0c;以及治理的成效&#xff0c;或许有朋友爱看。 政务数据&#xff0c;又称之为政务数据资源&a…

Linux最深刻理解页表于物理内存

目录 物理内存管理 页表设计 物理内存管理 如果磁盘上的内容加载到物理内存上&#xff0c;每次io都会按照4kb的方式进行加载(可能不同版本系统有些区别)。所以我们的物理内存上的内容也是4个字节进行管理的。 而每个页框都需要我们进行管理。所以自然物理内存就会对页框进行先…

一键高效管理:苹果手机如何一键删除照片

在我们的日常生活中&#xff0c;苹果手机不仅是沟通的工具&#xff0c;更是捕捉和保存生活瞬间的重要设备。随着时间的推移&#xff0c;数以千计的照片积累在设备中&#xff0c;这不仅占用了大量的存储空间&#xff0c;也可能影响设备的性能。本文将详细介绍苹果手机如何一键删…

C++:类和对象(二)

C&#xff1a;类和对象&#xff08;二&#xff09; 类的默认成员函数构造函数析构函数拷贝构造函数 类的默认成员函数 默认成员函数就是用户没有显式实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数。⼀个类&#xff0c;我们不写的情况下编译器会默认生成以下6个…

机器学习(基础2)

特征工程 特征工程:就是对特征进行相关的处理 一般使用pandas来进行数据清洗和数据处理、使用sklearn来进行特征工程 特征工程是将任意数据(如文本或图像)转换为可用于机器学习的数字特征,比如:字典特征提取(特征离散化)、文本特征提取、图像特征提取。 特征工程API 实例化…

ts中的元组概念解释(tuple)

用于定义数组每个元素的类型 元组 (Tuple) 是⼀种特殊的数组类型&#xff0c;可以存储固定数量的元素&#xff0c;并且每个元素的类型是已知的且可以不同。元组⽤于精确描述⼀组值的类型&#xff0c; ? 表示可选元素 1&#xff0c;正常写法 let list1 :[string,number] li…

Rust,删除cargo安装的可执行文件

列出安装的文件列表 cargo install --list 删除 rm /Users/ry/.cargo/bin/fancy

数据库中生成主键的方式及其优缺点

数据库中生成主键的方式及其优缺点 一、自动增长(AUTO_INCREMENT) 使用方法&#xff1a;设置auto_increment 实现数据表自增&#xff1b; 优点&#xff1a; 简单易用&#xff1a;自增主键是一种简单的方式&#xff0c;只需在数据库表中设置自增属性即可&#xff0c;无需在代…

linux进程管理

进程和线程的关系 以下介绍为linux环境 进程是操作系统中一个运行中的程序&#xff0c;是资源分配和调度的基本单位。每个进程有自己独立的内存空间、文件描述符、堆栈等系统资源 线程&#xff08;Thread&#xff09; 是 CPU 调度的最小单位&#xff0c;是进程中的一个执行流…