线程池,定时器以及阻塞队列(生产者/消费者模型)

💓 博客主页:从零开始的-CodeNinja之路

⏩ 收录专栏:线程池,定时器以及阻塞队列(生产者/消费者模型)

🎉欢迎大家点赞👍评论📝收藏⭐文章
在这里插入图片描述

实现线程池,定时器以及阻塞队列,生产者/消费者模型

  • 线程池
      • 线程池是什么
      • Executors创建线程池的四种方式
      • 线程池底层ThreadPoolExecutor的六大参数
      • 拒绝策略
      • 实现线程池
  • 定时器
      • 定时器的定义
      • 标准库中的定时器
      • 定时器的实现
  • 阻塞队列
      • 阻塞队列的概念
      • 生产者消费者模型
      • 阻塞队列实现(生产者/消费者模型)

在这里插入图片描述

在这里插入图片描述

线程池

线程池是什么

虽然创建线程/销毁线程的开销
线程池相当于是一个大池子,池子里放着默认的10个已创建的空闲的线程,每当使用时直接从池子里取出一个空闲的线程进行使用,使用完以后在放回池子里面,这样就减少了每次创建线程和销毁线程的资源浪费.

Executors创建线程池的四种方式

  • newFixedThreadPool:创建固定线程数的线程池
  • newCachedThreadPool:创建线程数目动态增长的线程池.
  • newSingleThreadExecutor:创建只包含单个线程的线程池.
  • newScheduledThreadPool:设定延迟时间后执行命令,或者定期执行命令.是进阶版的Timer.

线程池底层ThreadPoolExecutor的六大参数

Executors本质上是ThreadPoolExecutor类的封装.

ThreadPoolExecutor提供了更多的可选参数,可以进⼀步细化线程池行为的设定.

  • corePoolSize:正式员工的数量.正式员工,⼀旦录用,永不辞退)

  • maximumPoolSize:正式员工+临时工的数目.(临时工:⼀段时间不干活,就被辞退).

  • keepAliveTime:临时工允许的空闲时间.

  • unit:keepaliveTime的时间单位,是秒,分钟,还是其他值.

  • workQueue:传递任务的阻塞队列

  • threadFactory:创建线程的工厂,参与具体的创建线程工作.通过不同线程工厂创建出的线程相当于

对⼀些属性进行了不同的初始化设置.

拒绝策略

RejectedExecutionHandler:拒绝策略,如果任务量超出公司的负荷了接下来怎么处理.

  • AbortPolicy():超过负荷,直接抛出异常.
  • CallerRunsPolicy():调用者负责处理多出来的任务.
  • DiscardOldestPolicy():丢弃队列中最老的任务.
  • DiscardPolicy():丢弃新来的任务.

实现线程池

核心操作为submit,将任务加入线程池中

  1. 使⽤Worker类描述一个工作线程.使用Runnable描述⼀个任务.

  2. 使用一个BlockingQueue组织所有的任务

  3. worker线程要做的事情:不停的从BlockingQueue中取任务并执行.

  4. 指定⼀下线程池中的最大线程数maxWorkerCount;当当前线程数超过这个最大值时,就不再新增 线程了

.

class MyThreadPool {private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();// 通过这个⽅法, 来把任务添加到线程池中.public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}// n 表⽰线程池⾥有⼏个线程.
// 创建了⼀个固定数量的线程池.public MyThreadPool(int n) {for (int i = 0; i < n; i++) {Thread t = new Thread(() -> {while (true) {try {// 取出任务, 并执⾏~~Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}
}
// 线程池
public class Demo {public static void main(String[] args) throws InterruptedException {MyThreadPool pool = new MyThreadPool(4);for (int i = 0; i < 1000; i++) {pool.submit(new Runnable() {@Overridepublic void run() {
// 要执⾏的⼯作System.out.println(Thread.currentThread().getName() + " hell}});}}
}

定时器

定时器的定义

定时器也是软件开发中的⼀个重要组件.类似于⼀个"闹钟".达到⼀个设定的时间之后,就执行某个指定好的代码.
定时器是⼀种实际开发中非常常用的组件.
比如网络通信中,如果对方500ms内没有返回数据,则断开连接尝试重连.
比如⼀个Map,希望里面的某个key在3s之后过期(自动删除).

标准库中的定时器

  • 标准库中提供了⼀个Timer类.Timer类的核心方法为 schedule .
  • schedule 包含两个参数.第⼀个参数指定即将要执行的任务代码,第二个参数指定多长时间之后执行(单位为毫秒).
 Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello");}}, 3000);

定时器的实现

定时器的构成

  • ⼀个带优先级队列(不要使用PriorityBlockingQueue,容易死锁!)
  • 队列中的每个元素是⼀个Task对象.
  • Task中带有⼀个时间属性,队首元素就是即将要执行的任务
  • 同时有⼀个worker线程⼀直扫描队首元素,看队首元素是否需要执行
  1. Timer类提供的核心接口为schedule,用于注册⼀个任务,并指定这个任务多长时间后执行.
public class MyTimer {public void schedule(Runnable command, long after) {}}
  1. Task类用于描述⼀个任务(作为Timer的内部类).里面包含⼀个Runnable对象和⼀个time(毫秒时间戳)
    这个对象需要放到优先队列中.因此需要实现 Comparable 接口.
  class MyTask implements Comparable<MyTask> {public Runnable runnable;// 为了⽅便后续判定, 使⽤绝对的时间戳.public long time;public MyTask(Runnable runnable, long delay) {this.runnable = runnable;// 取当前时刻的时间戳 + delay, 作为该任务实际执⾏的时间戳this.time = System.currentTimeMillis() + delay;}@Overridepublic int compareTo(MyTask o) {
// 这样的写法意味着每次取出的是时间最⼩的元素.
// 到底是谁减谁?? 俺也记不住!!! 随便写⼀个, 执⾏下, 看看效果~~return (int)(this.time - o.time);}}
  1. Timer实例中,通过PriorityQueue来组织若干个Task对象.通过schedule来往队列中插⼀入个个Task对象.
class MyTimer {// 核⼼结构private PriorityQueue<MyTask> queue = new PriorityQueue<>();// 创建⼀个锁对象private Object locker = new Object();public void schedule(Runnable command, long after) {
// 根据参数, 构造 MyTask, 插⼊队列即可.synchronized (locker) {MyTask myTask = new MyTask(runnable, delay);queue.offer(myTask);locker.notify();}}
}
  1. Timer类中存在⼀个worker线程,⼀直不停的扫描队首 元素,看看是否能执行这个任务.所谓"能执行"指的是该任务设定的时间已经到达了.
 // 在这⾥构造线程, 负责执⾏具体任务了.public MyTimer() {Thread t = new Thread(() -> {while (true) {try {synchronized (locker) {
// 阻塞队列, 只有阻塞的⼊队列和阻塞的出队列, 没有阻塞的查看队⾸元素.while (queue.isEmpty()) {locker.wait();}MyTask myTask = queue.peek();long curTime = System.currentTimeMillis();if (curTime >= myTask.time) {
// 时间到了, 可以执⾏任务了queue.poll();myTask.runnable.run();} else {
// 时间还没到locker.wait(myTask.time - curTime);}}} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}

阻塞队列

阻塞队列的概念

阻塞队列是⼀种特殊的队列.也遵守"先进先出"的原则.
阻塞队列能是⼀种线程安全的数据结构,并且具有以下特性:

  • 当队列满的时候,继续⼊队列就会阻塞,直到有其他线程从队列中取走元素.
  • 当队列空的时候,继续出队列也会阻塞,直到有其他线程往队列中插入元素.

阻塞队列的⼀个典型应用场景就是"生产者消费者模型".这是⼀种非常典型的开发模型.

生产者消费者模型

生产者消费者模式就是通过⼀个容器来解决⽣产者和消费者的强耦合问题。
生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取.

1. 阻塞队列就相当于⼀个缓冲区,平衡了生产者和消费者的处理能力.(削峰填谷)

例如在"秒杀"场景下,服务器同⼀时刻可能会收到⼤量的⽀付请求.如果直接处理这些⽀付请求, 服务器可能扛不住(每个⽀付请求的处理都需要⽐较复杂的流程).这个时候就可以把这些请求都放到⼀个阻塞队列中,然后再由消费者线程慢慢的来处理每个⽀付请求. 这样做可以有效进行"削峰",防止服务器被突然到来的⼀波请求直接冲垮.

2. 阻塞队列也能使生产者和消费者之间解耦.

⽐如过年⼀家⼈⼀起包饺⼦.⼀般都是有明确分⼯,⽐如⼀个⼈负责擀饺⼦⽪,其他⼈负责包.擀饺⼦
⽪的⼈就是"⽣产者",包饺⼦的⼈就是"消费者".
擀饺⼦⽪的⼈不关⼼包饺⼦的⼈是谁(能包就⾏,⽆论是⼿⼯包,借助⼯具,还是机器包),包饺⼦的⼈也
不关⼼擀饺⼦⽪的⼈是谁(有饺⼦⽪就⾏,⽆论是⽤擀⾯杖擀的,还是拿罐头瓶擀,还是直接从超市买
的).

阻塞队列实现(生产者/消费者模型)

  • • 通过"循环队列"的方式来实现.
  • • 使用synchronized进行加锁控制.
  • • put插入元素的时候,判定如果队列满了,就进行wait.(注意,要在循环中进行wait被唤醒时不⼀定
    队列就不满了,因为同时可能是唤醒了多个线程).
  • • take取出元素的时候,判定如果队列为空,就进行wait.(也是循环wait)
import java.util.Random;public class BlockingQueue {private int[] items = new int[1000];private volatile int size = 0;private volatile int head = 0;private volatile int tail = 0;public void put(int value) throws InterruptedException {synchronized (this) {
// 此处最好使⽤ while.
// 否则 notifyAll 的时候, 该线程从 wait 中被唤醒,
// 但是紧接着并未抢占到锁. 当锁被抢占的时候, 可能⼜已经队列满了
// 就只能继续等待while (size == items.length) {wait();}items[tail] = value;tail = (tail + 1) % items.length;size++;notifyAll();}}public int take() throws InterruptedException {int ret = 0;synchronized (this) {while (size == 0) {wait();}ret = items[head];head = (head + 1) % items.length;size--;notifyAll();}return ret;}public synchronized int size() {return size;}// 测试代码public static void main(String[] args) throws InterruptedException {BlockingQueue blockingQueue = new BlockingQueue();Thread customer = new Thread(() -> {while (true) {try {int value = blockingQueue.take();System.out.println(value);} catch (InterruptedException e) {e.printStackTrace();}}}, "消费者");customer.start();Thread producer = new Thread(() -> {Random random = new Random();while (true) {try {blockingQueue.put(random.nextInt(10000));} catch (InterruptedException e) {e.printStackTrace();}}}, "⽣产者");producer.start();customer.join();producer.join();}
}

在这里插入图片描述
如果觉得文章不错,期待你的一键三连哦,你个鼓励是我创作的动力之源,让我们一起加油,顶峰相见!!!💓 💓 💓

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

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

相关文章

clickhouse如何清除多个分区数据 alter table drop partition操作

官网drop partition操作 官网链接&#xff1a;https://clickhouse.com/docs/zh/sql-reference/statements/alter/partition#drop-partitionpart 官网上之有清除单个分区的例子&#xff0c;并没有对清除多个分区的场景进行描述&#xff0c;之前清除分区时也是按照官网例子进行…

探索前端开发框架:React、Angular 和 Vue 的对决(一)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

clickhouse在MES中的应用-跟踪扫描

开发的MES&#xff0c;往往都要做生产执行跟踪扫描&#xff0c;这样会产生大量的扫描数据&#xff0c;用关系型数据库&#xff0c;很容易造成查询冲突的问题。 生产跟踪扫描就发生的密度是非常高的&#xff0c;每个零部件的加工过程&#xff0c;都要被记录下来&#xff0c;特别…

Photoshop效率神器:10款必备PS插件

Camera Raw Cameraaaps插件Camera Raw是一款相机增强插件&#xff0c;您可以用它来编辑和增强数码相机中的RAW文件、JPEG和TIFF文件&#xff0c;Camera Raw将分析相机中的原始数据&#xff0c;实现白平衡、锐化、对比度、色调等参数的一键调整。 Texture Anarchy TexturePS插…

Keepalived + DR 集群

目录 1、Keepalive VRRP 说明 故障切换 工作原理 核心组件 2、Keepalived DR 集群 拓扑规划 前期准备 配置 Httpd 服务 配置 Nginx 服务 配置 LVS 主 node_01 配置 LVS 从 node_02 测试 LVS 集群 测试主备切换 3、Keepalived 脑裂现象 4、Keepalived 心态检测 …

git将项目的某次签入遴选(Cherry-Pick)另一个项目

需求&#xff1a;将项目Product&#xff0c;分支feature/platform&#xff0c;签入959294ce6b75ee48c5cb22c46d7398654628a896&#xff0c;遴选到项目BRP&#xff0c;分支dev 第一步&#xff1a;使用原签入生成patch文件&#xff08;git format-patch -1 <commit_hash>&a…

[网络安全]IIS---FTP服务器 、serverU详解

一 . FTP服务器(File Transfor Protocol) : 协议:文件传输协议 端口号:TCP: 20(数据) / 21(控制) 二 . FTP工作方式: 1.主动模式 : (FTP服务器21端口与FTP客户端产生的随机端口先建立连接 建立连接后,再使用FTP服务器21端口与FTP客户端创建的一个新的随机端口进行发送…

用Python Tkinter打造的精彩连连看小游戏【附源码】

文章目录 连连看小游戏&#xff1a;用Python Tkinter打造的精彩游戏体验游戏简介技术背景MainWindow类:职责:方法:Point类: 主执行部分:完整代码&#xff1a;总结&#xff1a; 连连看小游戏&#xff1a;用Python Tkinter打造的精彩游戏体验 在丰富多彩的游戏世界中&#xff0c…

海外云手机开辟企业跨境电商新道路

近几年&#xff0c;海外云手机为跨境电商、海外媒体引流、游戏行业等互联网领域注入了蓬勃活力。对于国内跨境电商而言&#xff0c;在亚马逊及其他平台上&#xff0c;短视频引流和社交电商营销成为最为有效的流量来源。如何通过海外云手机的助力&#xff0c;在新兴社交平台为企…

有趣的CSS - 鼠标悬浮线条动态变化

鼠标悬浮线条动态变化 整体效果核心代码html 代码&#xff1a;css 部分代码&#xff1a; 完整代码如下html 页面&#xff1a;css 样式&#xff1a;页面渲染效果&#xff1a; 整体效果 这个链接悬浮效果主要用 css3 的 animation 属性配合 :hover 伪选择器来实现的。 此效果可以…

【华为】GRE Over IPsec 实验配置

【思科】GRE Over IPsec 实验配置 前言报文格式 实验需求配置拓扑GRE配置步骤IPsec 配置步骤R1基础配置GRE 配置IPsec 配置 ISP_R2基础配置 R3基础配置GRE 配置IPsec 配置 PCPC1PC2 抓包检查OSPF建立GRE隧道建立IPsec 隧道建立Ping 配置文档 前言 GRE over IPSec可利用GRE和IP…

[python]基于LSTR车道线实时检测onnx部署

【框架地址】 https://github.com/liuruijin17/LSTR 【LSTR算法介绍】 LSTR车道线检测算法是一种用于识别和定位车道线的计算机视觉算法。它基于图像处理和机器学习的技术&#xff0c;通过对道路图像进行分析和处理&#xff0c;提取出车道线的位置和方向等信息。 LSTR车道线…

MySQL库表操作 作业

题目&#xff1a; 1. sql语句分为几类?2. 表的约束有哪些,分别是什么,设置的语法分别是什么?3. 做出班级表,学生表的E-R图,数据库模型图,以及核心的sql语句. 1. MySQL致力于支持全套ANSI/ISO SQL标准。在MySQL数据库中&#xff0c;SQL语句主要可以划分为以下几类: > DD…

计算机网络-调度算法-2(时间片轮转 优先级调度算法 多级反馈队列调度算法 多级队列调度算法)

文章目录 总览时间片轮转时间片大小为2时间片大小为5若按照先来先服务算法 优先级调度算法例题&#xff08; 非抢占式优先级调度算法&#xff09;例题&#xff08; 抢占式优先级调度算法&#xff09;补充 思考多级反馈队列调度算法例题 小结多级队列调度算法 总览 时间片轮转 …

ElementUI Form:Form表单

ElementUI安装与使用指南 Form表单 点击下载learnelementuispringboot项目源码 效果图 el-form.vue&#xff08;Form表单&#xff09;页面效果图 项目里 el-form.vue代码 <script> export default {name: el_form,data() {var checkAge (rule, value, callback…

LabVIEW核能设施监测

LabVIEW核能设施监测 在核能领域&#xff0c;确保设施运行的安全性和效率至关重要。LabVIEW通过与硬件的紧密集成&#xff0c;为高温气冷堆燃料装卸计数系统以及脉冲堆辐射剂量监测与数据管理系统提供了解决方案。这些系统不仅提高了监测和管理的精确度&#xff0c;也保证了核…

JVM之Java内存区域

JVM-Java内存区域 Java内存区域是Java虚拟机&#xff08;JVM&#xff09;管理的内存资源的逻辑划分&#xff0c;用于存储程序运行时所需的数据。Java内存区域的合理划分和管理对于程序的性能和稳定性具有重要影响。本文将深入探讨Java内存区域的各个部分&#xff0c;包括方法区…

比特币ETF广告战大爆发!

作者&#xff1a;秦晋 贝莱德主动发起广告攻势。 2月1日&#xff0c;据外媒Cryptoslate报道&#xff0c;贝莱德在提交给美国SEC的一份文件中显示&#xff0c;其提出一项在建筑物侧面投影比特币ETF广告计划。 据介绍&#xff0c;广告内容为&#xff1a;「IBIT」信号是一个以迈阿…

JAVA Web 学习(四)RabbitMQ、Zookeeper

十、消息队列服务器——RabbitMQ RabbitMQ是使用Erlang语言开发的开源消息队列系统&#xff0c;基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、 安全。AMQP协议更多用在企业系统内&#xff0c;对数据一致性、稳定性和可靠性要求…

QT研究笔记(一)windows 开发环境安装部署

一、Qt 是什么&#xff1f; Qt 是一个跨平台的应用程序开发框架&#xff0c;最初由挪威的 Trolltech 公司开发&#xff0c;并于2008年被诺基亚收购。后来&#xff0c;Qt 框架由 Digia 公司接手&#xff0c;并在2012年成立了 The Qt Company。Qt 提供了一套丰富的工具和类库&am…