Java多线程编程(四)- 阻塞队列,生产者消费者模型,线程池

目录:

 一.阻塞队列 

二.线程池

 一.阻塞队列 

 1.阻塞队列是⼀种特殊的队列. 也遵守 "先进先出" 的原则 

阻塞队列能是⼀种线程安全的数据结构, 并且具有以下特性:
1.1.当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素 
1.2.队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素 

阻塞队列最主要的应用场景--->生产者消费者模型

2.生产者消费者模型的优点:

解耦合:

两个线程或者两个服务器之间如果直接访问,那么他们的耦合度就会很高,这个时候如果加入阻塞队列,让这两个服务器分别和这个阻塞队列交互,就会达到解耦合的目的 

削峰填谷: 

 阻塞队列的重要程度不小,所以也会直接会搞成几个服务器 

 


缺点: 

(1).效率会降低

(2).部署更多服务器生产环境复杂,管理起来比较麻烦


3.生产者消费者模型的实现:

自己实现一个阻塞队列,实现生产者消费者模型 

代码: 

class MyBlockingQueue{private String[] data = null;private int head = 0;//队首private int tail = 0;//队尾private int size = 0;//元素个数MyBlockingQueue(int capacity){data = new String[capacity];}//入队列public void put(String elem) throws InterruptedException {synchronized (this) {while (size >= data.length) {//阻塞this.wait();//队列不满时唤醒,其他线程take}data[tail] = elem;//        tail = (tail+1) % data.length;tail++;if (size >= data.length) {tail = 0;}size++;this.notify();}}public String take() throws InterruptedException {synchronized (this) {while (size == 0) {//阻塞this.wait();//队列不空时唤醒,其他线程put}String ret = data[head];head++;if (size >= data.length) {head = 0;}//        head = (head+1) % data.length;size--;this.notify();return ret;}}}

使用: 至少一个生产者线程,一个消费者线程

 public static void main(String[] args) {MyBlockingQueue queue = new MyBlockingQueue(100);Thread producer = new Thread(()->{int n = 0;while (true){try {queue.put(n + "");System.out.println("生产元素 " + n);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}n++;}},"producer ");Thread consumer = new Thread(()->{while (true){try {String n = queue.take();System.out.println("消费元素 " + n);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}},"consumer ");producer.start();consumer.start();}

现象:这里Sleep加在生产者哪,导致产生的慢,队列可能为空阻塞,导致生产一个消费一个 

  


4.标准库中的阻塞队列: 
在 Java 标准库中内置了阻塞队列. 如果我们需要在⼀些程序中使⽤阻塞队列, 直接使⽤标准库中的即可.
BlockingQueue 是⼀个接口. 真正实现的类是 有链表类型LinkedBlockingQueue.
也有循环数组类型ArrayBlockingQueue

注意:
put 方法用于阻塞式的⼊队列, take ⽤于阻塞式的出队列.
BlockingQueue 也有 offer, poll, peek 等⽅法, 但是这些方法不带有阻塞特性 
 
public static void main(String[] args) {BlockingQueue<Integer> queue = new LinkedBlockingDeque<>();Thread producer = new Thread(()->{int n = 0;while (true){try {queue.put(n);System.out.println("生产元素 " + n);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}n++;}},"producer ");Thread consumer = new Thread(()->{while (true){try {Integer n = queue.take();System.out.println("消费元素 " + n);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}},"consumer ");producer.start();consumer.start();}


二.线程池 :

1.线程是什么?

里面有大量的线程可以直接给我们使用,不用系统去创建让我们高效的创建销毁线程,就和常量池类似,在Java程序构建时候准备好,等程序运行时直接加载到内存中使用 


2.为什么要有线程池?

就是让我们高效的创建销毁线程,就像创建进程太慢了引入线程一样的道理。 


3. 为什么直接从线程池取线程比创建线程快?

因为操作中唯一,一份内核要为很多应用程序提供服务,相当于创建线程交给了操作系统,这是不可控的 (如果要创建线程A,而操作系统有很多线程,创建分配资源是不可控的,可能很晚才轮到A,所以还不如,通过代码的方式创建好线程这样就可控且高效) 

4.Java标准库中的线程池: 

ThreadPoolExecutor里有一些线程可以让这些线程执行任务主要涉及的方法有:

核心方法submit(Runnable),  

Runnable描述一段要执行的任务

submit把任务放到线程池中执行 


构造ThreadPoolExecutor这个类构造方法最多有7个

 接下来我们来分析这7个参数


注:Java线程池中有几个线程任务多时自动创建出多个线程,任务少时会销毁 

corePoolSize:为核心线程数,核心线程在线程池创建时就创建,一直到线程池销毁才会跟着销毁

maximumPoolSize: 为最大线程数 (核心线程+非核心线程)非核心线程就是上面说的线程任务多时自动创建出多个线程,任务少时会销毁 


keepAliveTime: 非核心线程允许存活的最大时间,(非核心线程不是任务少时立即销毁,会有一段存活时间) 

 

unit: 定义一些枚举,比如上面线程存活时间,的时间


workQueue:工作队列(阻塞队列)(线程池的本质也是,生产者消费者模型,调用submit就是在生产任务,线程池则消费任务,线程池相当于消费者) 


threadFactory: 工厂模式(工厂模式也属于一种设计模式),弥补构造方法的缺陷,但是在构造方法上有时候无法重载,如果必须要系统类型的参数时

  

这个时候就可以单独封装一个工厂类去实现构造,用静态的方法,把构造对象过程和各种属性初始化封装起来。

class PointFactory {public static Point makePointByXY(double x, double y) {Point p = new Point();// 通过 x 和 y 给 p 进行属性设置return p;}public static Point makePointByRA(double r, double a) {Point p = new Point();// 通过 r 和 a 给 p 进行属性设置return p;}
}

handler: 拒绝策略,submit方法把任务添加到阻塞队列中不会阻塞(阻塞会影响客户端的体验),而是使用拒绝策略 ;具体怎么拒绝还要引入四个类说明: 

(1).AbortPolicy: 线程池直接抛出异常,可能导致线程池无法继续工作。

(2).CallerRunsPolicy: 让调用submit方法的线程自己去执行任务

(submit方法里可能先判断队列是否满,如果满了再判断是否执行CallerRunsPolicy策略,如果要执行,就调用里面的Runnable.run;让调用者线程自己去执行任务)

(3).DiscardOldesPolicy: 丢弃队列中最老的任务

(4).DiscardPolicy: 丢弃队列中最新的任务(当前submit这个任务)


5.Java标准库也提供了另外一组类Executors,对ThreadPoolExecutor这个类进一步封装,来简化线程池的使用,由于被进一步封装线程数目和拒绝策略是隐式的,规模大业务多的公司不好控制,所以阿里巴巴编程规范手册里,不推荐使用,但是大多数公司还是支持的具体看公司规范。

newFixedThreadPool: 创建固定线程数的线程池
newCachedThreadPool: 创建线程数⽬动态增⻓的线程池.
newSingleThreadExecutor: 创建只包含单个线程的线程池
 

6.自己实现线程池:

线程池相当于消费者,消费阻塞队列里的任务,线程池的实现也是基于生产者消费者模型的: 

package demo;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;/*** Created with IntelliJ IDEA.* Description:* User: 苏李涛* Date: 2024-10-22* Time: 16:48*/// 实现一个固定线程个数的线程池class MyThreadPool{BlockingQueue<Runnable> queue = null;MyThreadPool(int n){// 初始化线程池,创建固定个数的线程// 这里使用ArrayBlockingQueue作为任务队列, 容量为1000queue = new ArrayBlockingQueue<>(1000);// 创建 N 个线程for(int i = 0; i < n; i++) {Thread t = new Thread(()->{try {while (true){Runnable task = queue.take();task.run();}}catch (InterruptedException e){e.printStackTrace();}});t.setDaemon(true);//把线程设置为后台线程,方便结束,注意:此方法必须在线程启动之前调用t.start();}}public void submit(Runnable task){task.run();}}public class Demo1 {public static void main(String[] args) {MyThreadPool pool = new MyThreadPool(10);// 向线程池提交任务for (int i = 0; i < 100; i++) {int id = i;pool.submit(()->{System.out.println(Thread.currentThread().getName() +" "+ "id=" + id);});}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

open3d

open3d open3d用于 3D 数据处理的现代库。 简介 Open3D 是一个开源库&#xff0c;支持快速开发处理 3D 数据的软件。Open3D 前端公开了一组精心挑选的 C 和 Python 数据结构和算法。后端经过高度优化&#xff0c;并设置为并行化。Open3D 是从零开始开发的&#xff0c;具有一更…

洞察鸿蒙生态,把握开发新机遇

随着科技的不断进步&#xff0c;鸿蒙系统以其独特的分布式架构和跨设备协同能力&#xff0c;逐渐在智能手机、智能穿戴、车载、家居等多个领域崭露头角&#xff0c;与安卓、iOS形成三足鼎立之势。作为一名开发者&#xff0c;我对鸿蒙生态的认知和了解如下&#xff1a; 一、鸿蒙…

adb 如何通过wifi连接手机

1. 电脑通过USB线连接手机 1.1手机开启开发者模式 以小米手机为例&#xff1a;连续点击OS版本系统&#xff08;设置–>我的设备–>全部参数&#xff09; 1.2在开发者模式下&#xff0c;启动允许USB安装与USB调试 操作步骤&#xff1a;设置>更多设置>开发者选项&g…

【webrtc】 RTP 中的 MID(Media Stream Identifier)

RTP 中的 MID(Media Stream Identifier) RID及其与MID的区别 cname与mid的对比【webrtc】CNAME 是rtprtcp中的Canonical Name(规范化名称) 同样都是RTP头部扩展: 基于mediasoup的最新的代码,学习,发现mid在创建RtpSendStream时是必须传递的参数: 例如 D:\XTRANS\soup\…

brother:什么是兄弟,你悟了吗?

brother&#xff08;兄弟&#xff09;这个单词好奇怪哦&#xff0c;它为什么就会是兄弟呢&#xff1f;为什么这样书写、这些字母组合在一起&#xff0c;就是兄弟呢&#xff1f;而且&#xff0c;西方人的兄弟brother一词和姐妹sister一词&#xff0c;并不是像中国人所称呼明确指…

如何在谷歌浏览器中优化内存使用

在日常使用电脑的过程中&#xff0c;我们经常会遇到系统资源被大量占用的情况&#xff0c;尤其是内存。谷歌浏览器作为一个广泛使用的网络浏览器&#xff0c;其内存占用问题也备受关注。本文将详细介绍如何在谷歌浏览器中优化内存使用&#xff0c;以提升浏览体验和系统性能。&a…

谷歌浏览器支持的开发者工具详解

谷歌浏览器&#xff08;Google Chrome&#xff09;是全球最受欢迎的网页浏览器之一&#xff0c;它不仅提供了快速、安全的浏览体验&#xff0c;还为开发者提供了强大的开发者工具。本文将详细介绍如何使用谷歌浏览器的开发者工具&#xff0c;并解答一些常见问题。&#xff08;本…

推荐一款多物理场模拟仿真软件:STAR-CCM+

Siemens STAR-CCM是一款功能强大的计算流体力学(CFD)软件&#xff0c;由西门子公司推出。它集成了现代软件工程技术、先进的连续介质力学数值技术和卓越的设计&#xff0c;为工程师提供了一个全面的多物理场仿真平台。主要特点与优势&#xff1a;多物理场仿真、自动化与高效、高…

无人机飞手考证,地面站培训技术详解

无人机飞手考证及地面站培训技术涉及多个关键方面&#xff0c;以下是对这些方面的详细解析&#xff1a; 一、无人机飞手考证流程与要求 1. 证书类型 民用无人机驾驶员证书&#xff1a;这是国家民航局颁发的无人机操作人员资质证书&#xff0c;分为视距内驾驶员、超视距驾驶员…

SpringMVC全面复习

Javaweb SpringMVC Spring MVC是Spring框架的一个模块&#xff0c;专门用于构建Web应用程序的模型-视图-控制器&#xff08;MVC&#xff09;架构。它通过清晰的分离关注点&#xff0c;简化了Web应用各部分的开发。Spring MVC提供了强大的绑定机制&#xff0c;能够将请求参数绑定…

python基础大杂烩

命令提示符程序&#xff0c;输入python&#xff0c;运行python程序 代码通过解释器程序翻译给计算机去执行 命令提示符输入的python本质上就是调用D:/dev/python/python3.12.5/python.exe这个解释器程序 有python程序将输入的代码翻译成二进制的0和1&#xff0c;去向计算机去运…

MathGPT的原理介绍,在中小学数学教学的应用场景,以及代码样例实现

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下MathGPT的原理介绍&#xff0c;在中小学数学教学的应用场景&#xff0c;以及代码样例实现。MathGPT的核心架构是一个精心设计的多层次系统&#xff0c;旨在有效处理复杂的数学问题。其主要组成部分包括 数学知识图谱…

算法演练----24点游戏

给定4个整数&#xff0c;数字范围在1~13之间任意使用-*/&#xff08;&#xff09;&#xff0c;构造出一个表达式&#xff0c;使得最终结果为24&#xff0c; 方法一 算法分析&#xff1a;加括号和取出重复表达式 # 导入精确除法模块&#xff0c;使得在Python2中除法运算的行为更…

关于指针p有关的3个值

1&#xff0c;他的类型是int*; 2,*p是解用&#xff0c;指向的是对象 3&#xff0c;&p指向的是p的地址&#xff0c;是指针的地址

《JavaEE进阶》----20.<基于Spring图书管理系统①(登录+添加图书)>

PS&#xff1a;关于接口定义 接口定义&#xff0c;通常由服务器提供方来定义。 1.路径&#xff1a;自己定义 2.参数&#xff1a;根据需求考虑&#xff0c;我们这个接口功能完成需要哪些信息。 3.返回结果&#xff1a;考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的…

Linux服务管理-iSCSI

iSCSI 基础知识 iSCSI&#xff08;Internet Small Computer System Interface&#xff09;协议是一种基于IP网络的存储协议&#xff0c;它允许主机&#xff08;计算机或服务器&#xff09;通过TCP/IP网络访问远程存储设备。该协议具有以下主要特点&#xff1a; 灵活性&#xf…

快速掌握——python类 封装[私有属性方法]、继承【python进阶】(内附代码)

1.类的定义 与 实例化对象 在python中使用class关键字创建一个类。 举例子 class Stu(object):id 1001name 张三def __init__(self):passdef fun1(self):pass# 实例化对象 s1 Stu() s2 Stu() print(s1.name) print(s2.name) 第一个方法 __init__是一种特殊的方法&#x…

HarmonyOS 如何实现传输中的数据加密

文章目录 摘要引言数据传输加密概述选择加密算法和传输协议加密实现方案与 Demo 代码配置 HTTPS/TLSAES 加密的实现代码详解RSA加密的实现代码详解 QA环节总结参考资料 摘要 本文将介绍在 HarmonyOS 应用中如何实现数据传输的加密策略。我们将讨论常见的加密算法&#xff08;如…

Bilibili-超能用户榜入口优化-技术方案反思与总结

目录 客户端实现&#xff1a; 高能用户入口实现逻辑&#xff1a; 接口服务信息&#xff08;服务端下发&#xff09;&#xff1a; 执行方案&#xff1a; (1)数据类新增服务端下发字段 ​编辑 (2) UI添加 寻找思路&#xff1a; &#xff08;3&#xff09;超能用户icon显示…

vue实现图片无限滚动播放

本人vue新手菜鸡&#xff0c;文章为自己在项目中遇到问题的记录&#xff0c;如有不足还请大佬指正 文章目录 实现效果代码展示总结 因为刚接触vue&#xff0c;本想着看看能不能用一些element的组件实现图片的轮播效果&#xff0c;尝试使用过element-UI里的走马灯Carouse&#x…