JUC的线程池架构
🙈作者简介:练习时长两年半的Java up主
🙉个人主页:程序员老茶
🙊 ps:点赞👍是免费的,却可以让写博客的作者开心好久好久😎
📚系列专栏:Java全栈,计算机系列(火速更新中)
💭 格言:种一棵树最好的时间是十年前,其次是现在
🏡动动小手,点个关注不迷路,感谢宝子们一键三连
目录
- 课程名:Java
- 内容/作用:知识点/设计/实验/作业/练习
- 学习:JUC的线程池架构
- JUC的线程池架构
- 一、线程池的基本概念
- 二、线程池的使用方法
- 1. 创建线程池
- 2. 提交任务到线程池
- 3. 关闭线程池
- 三、线程池的核心组件
- 1. ThreadPoolExecutor
- 2. BlockingQueue
- 3. 拒绝策略
- 四、自定义线程池示例
- 1. 创建自定义线程池
- 2. 使用自定义线程池
课程名:Java
内容/作用:知识点/设计/实验/作业/练习
学习:JUC的线程池架构
JUC的线程池架构
本文主要介绍Java中如何使用java.util.concurrent包中的线程池(ExecutorService和ThreadPoolExecutor)来实现高并发、高可用的系统。我们将从线程池的基本概念、使用方法、核心组件以及自定义线程池四个方面进行阐述。
一、线程池的基本概念
线程池是一种管理线程的机制,它可以有效地控制线程的数量,避免大量线程之间的切换导致性能下降。线程池中的线程可以被复用,当一个任务完成后,线程不会被销毁,而是被重新分配给新的任务。
二、线程池的使用方法
1. 创建线程池
在Java中,可以通过Executors工具类来创建不同类型的线程池。例如,创建一个固定大小的线程池:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDemo {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(5);}
}
2. 提交任务到线程池
使用submit()方法将任务提交到线程池中执行:
executorService.submit(new Runnable() {@Overridepublic void run() {System.out.println("任务执行中...");}
});
3. 关闭线程池
当所有任务都执行完毕后,需要关闭线程池以释放资源:
executorService.shutdown();
三、线程池的核心组件
1. ThreadPoolExecutor
ThreadPoolExecutor是ExecutorService接口的实现类,它提供了更多的功能,如定时执行、定期执行、异常处理等。我们通常需要自己实现一个ThreadPoolExecutor来满足业务需求。
2. BlockingQueue
BlockingQueue是一个阻塞队列,用于存放待处理的任务。它是一个FIFO(先进先出)的队列,当队列满时,新来的任务会等待;当队列为空时,正在执行的任务会等待。常用的阻塞队列有ArrayBlockingQueue、LinkedBlockingQueue和SynchronousQueue。
3. 拒绝策略
当线程池无法处理新提交的任务时,需要采取一定的策略来处理这些任务。Java中的RejectedExecutionHandler接口提供了四种默认的拒绝策略:
CallerRunsPolicy:直接在调用者线程中运行任务。AbortPolicy:抛出一个未检查异常中断任务。DiscardPolicy:丢弃任务,不做任何处理。DiscardOldestPolicy:丢弃队列中最旧的任务,尝试重新提交新任务。
我们可以根据实际需求自定义拒绝策略。例如,下面是一个自定义的拒绝策略示例:
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {private static final int MAX_CAPACITY = 100; // 最大容量private AtomicInteger rejectedCount = new AtomicInteger(); // 被拒绝的任务计数器private ArrayBlockingQueue<Runnable> taskQueue; // 任务队列public CustomRejectedExecutionHandler() {taskQueue = new ArrayBlockingQueue<>(MAX_CAPACITY); // 初始化任务队列}@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // 拒绝策略实现方法if (taskQueue.remainingCapacity() == 0) { // 如果队列已满,添加拒绝策略executor.setRejectedExecutionHandler(new RejectedExecutionHandler() { // 设置新的拒绝策略@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // 拒绝策略实现方法(AbortPolicy)System.err.println("Task queue is full, rejecting task: " + r); // 输出错误信息并抛出异常(AbortPolicy)throw new RejectedExecutionException("Task queue is full", r); // 抛出RejectedExecutionException异常(AbortPolicy)}});} else { // 如果队列未满,将任务添加到队列中,并增加计数器(CallerRunsPolicy)或直接抛出异常(DiscardPolicy/DiscardOldestPolicy)taskQueue.put(r); // 将任务添加到队列中(非阻塞)rejectedCount.incrementAndGet(); // 被拒绝的任务计数器加1(CallerRunsPolicy/DiscardPolicy/DiscardOldestPolicy)或直接抛出异常(DiscardPolicy/DiscardOldestPolicy)}}
}
四、自定义线程池示例
下面我们通过一个示例来说明如何自定义线程池:假设我们需要一个支持定时执行和周期性执行的任务线程池,我们可以这样实现:
要实现一个支持定时执行和周期性执行的任务线程池,我们可以创建一个自定义的线程池类,继承自ThreadPoolExecutor,并重写其中的方法。以下是一个简单的示例:
import java.util.concurrent.*;public class CustomThreadPoolExecutor extends ThreadPoolExecutor {private final long keepAliveTime;private final TimeUnit unit;public CustomThreadPoolExecutor(int corePoolSize, long keepAliveTime, TimeUnit unit) {super(corePoolSize);this.keepAliveTime = keepAliveTime;this.unit = unit;}@Overrideprotected void beforeExecute(Thread t, Runnable r) {super.beforeExecute(t, r);// 在任务执行前执行的操作,例如记录日志、初始化资源等}@Overrideprotected void afterExecute(Runnable r, Throwable t) {super.afterExecute(r, t);// 在任务执行后执行的操作,例如清理资源、记录日志等}public void scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {super.scheduleAtFixedRate(command, initialDelay, period, unit);}public void scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {super.scheduleWithFixedDelay(command, initialDelay, delay, unit);}
}
在这个示例中,我们创建了一个名为CustomThreadPoolExecutor的自定义线程池类,它继承自ThreadPoolExecutor。我们为这个类添加了两个方法:scheduleAtFixedRate和scheduleWithFixedDelay,分别用于定时执行和周期性执行任务。这两个方法内部调用了父类的相应方法来实现任务调度。
使用这个自定义线程池的示例代码如下:
import java.util.concurrent.*;public class CustomThreadPoolExample {public static void main(String[] args) throws InterruptedException {CustomThreadPoolExecutor threadPool = new CustomThreadPoolExecutor(2, 10, TimeUnit.SECONDS);for (int i = 0; i < 5; i++) {final int taskId = i;threadPool.execute(() -> {System.out.println("Task " + taskId + " is running");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Task " + taskId + " is completed");});}// 关闭线程池(所有任务执行完成后,线程池不再接受新任务)threadPool.shutdown();}
}
在这个示例中,我们创建了一个定时执行任务的线程池,核心线程数为2,任务间隔时间为10秒。然后,我们提交了5个任务到线程池,每个任务打印一条开始和结束信息,并在运行过程中暂停1秒。由于线程池具有定时执行功能,因此这些任务会按照设定的时间间隔依次执行。最后,我们在所有任务执行完成后关闭线程池。
在Java中,我们可以通过java.util.concurrent.Executors类创建线程池。然而,有时候我们需要创建一个具有特定功能的线程池,例如定时执行任务、周期性执行任务等。这时,我们可以创建一个自定义的线程池来实现这些功能。本文将介绍如何创建一个自定义线程池,并通过一个示例来演示其使用方法。
1. 创建自定义线程池
要创建一个自定义线程池,我们需要实现java.util.concurrent.ThreadPoolExecutor接口,并重写其中的方法。以下是一个简单的自定义线程池实现:
import java.util.concurrent.*;public class CustomThreadPoolExecutor extends ThreadPoolExecutor {private final int corePoolSize;private final BlockingQueue<Runnable> workQueue;private final long keepAliveTime;private final TimeUnit unit;public CustomThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> workQueue, long keepAliveTime, TimeUnit unit) {this.corePoolSize = corePoolSize;this.workQueue = workQueue;this.keepAliveTime = keepAliveTime;this.unit = unit;}@Overrideprotected void beforeExecute(Thread t, Runnable r) {super.beforeExecute(t, r);// 在任务执行前执行的操作,例如记录日志、初始化资源等}@Overrideprotected void afterExecute(Runnable r, Throwable t) {super.afterExecute(r, t);// 在任务执行后执行的操作,例如清理资源、记录日志等}
}
2. 使用自定义线程池
创建好自定义线程池后,我们可以像使用普通的ThreadPoolExecutor一样使用它。以下是一个使用自定义线程池的示例:
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;public class CustomThreadPoolExample {public static void main(String[] args) {// 创建一个定时执行任务的线程池CustomThreadPoolExecutor threadPool = new CustomThreadPoolExecutor(2, new LinkedBlockingQueue<>(2), 30, TimeUnit.SECONDS);// 提交任务到线程池for (int i = 0; i < 5; i++) {final int taskId = i;threadPool.execute(() -> {System.out.println("Task " + taskId + " is running");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Task " + taskId + " is completed");});}// 关闭线程池(所有任务执行完成后,线程池不再接受新任务)threadPool.shutdown();}
}
在这个示例中,我们创建了一个定时执行任务的线程池,最大容量为2,任务队列大小为2,空闲线程的存活时间为30秒。然后,我们提交了5个任务到线程池,每个任务打印一条开始和结束信息,并在运行过程中暂停1秒。由于线程池具有定时执行功能,因此这些任务会按照设定的时间间隔依次执行。最后,我们在所有任务执行完成后关闭线程池。
| 往期专栏 |
|---|
| Java全栈开发 |
| 数据结构与算法 |
| 计算机组成原理 |
| 操作系统 |
| 数据库系统 |
| 物联网控制原理与技术 |
相关文章:
JUC的线程池架构
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开心好久好久😎 📚系列专栏:Java全栈,…...
PostgreSQL limit 语法
PostgreSQL limit 语法 LIMIT 是 PostgreSQL 中用于限制查询结果数量的关键字。其语法如下: SELECT column1, column2, ... FROM table_name LIMIT number_of_rows;其中,SELECT 语句用于指定要查询的列和数据表,LIMIT 用于指定查询结果的行…...
CUDA C编程权威指南:2.1-CUDA编程模型
本文主要通过例子介绍了CUDA异构编程模型,需要说明的是Grid、Block和Thread都是逻辑结构,不是物理结构。实现例子代码参考文献[2],只需要把相应章节对应的CMakeLists.txt文件拷贝到CMake项目根目录下面即可运行。 1.Grid、Block和Thread间的…...
两条记录合并成一条记录
两条记录合并成一条记录 两条记录 val4,type_idlevel 和 val6,type_idtypeId 合并成一条记录 level4,typeId6 可以使用 条件聚合语句 CASE WHEN … 和 MAX 函数来实现。假设有以下 my_table 表: --------------------- | id | val | type_id | --------------…...
vue3 + typescript + vite + naive ui + tailwindcss + jsx 仿苹果桌面系统
基于 vue3.x typescript vite naive ui tailwindcss jsx vue-router pinia,项目使用 tsx 作为模版输出,全程没有使用vue提供的SFC, 仿macos桌面前端项目,开源免费模版,希望减少工作量和学习新技术,希…...
揭秘,用软件一秒识别纸质表格数字,找到你想要的一串数字
要将纸质表格的数字快速用软件识别并找出特定的一串数字,以下是三种常用的方案: 方案一:使用OCR软件识别和搜索功能 1. 扫描纸质表格并保存为图像或PDF格式。 2. 使用OCR(光学字符识别)软件,如金鸣表格文字…...
解析图片文件格式
图片文件幻数 关于JPEG格式 二进制形式打开文件,文件开始字节为FF D8,文件结束两字节为FF D9 JPEG 文件有两种不同的元数据格式:JFIF 和 EXIF。 JFIF 以 ff d8 ff e0 开头,EXIF 以 ff d8 ff e1 开头。 代码示例 private static…...
新的“HTTP/2 快速重置”零日攻击打破了 DDoS 记录
自 8 月份以来,一种名为“HTTP/2 快速重置”的新 DDoS(分布式拒绝服务)技术已被作为零日漏洞积极利用,其规模打破了之前的所有记录。 Amazon Web Services、Cloudflare 和 Google 今天联合发布了有关零日技术的消息,他…...
现代化战机之路:美国空军U-2侦察机基于Jenkins和k8s的CI/CD架构演进
▲ 点击上方"DevOps和k8s全栈技术"关注公众 华为北京研究所Q27大楼 随着技术的不断进步,军事领域也在积极采纳现代化工具来提高战备水平和效率。美国空军的U-2侦察机项目是一个鲜明的例子,它成功地借助Jenkins和Kubernetes(k8s&…...
Linux中常用的软件:Squid
在Linux系统中,有许多不同的代理软件可供选择。本文将比较两个常用的代理软件: Squid。我们将介绍它们的特点、使用场景和优缺点,帮助您选择适合自己需求的代理软件。 - 支持多种加密协议,包括AES、ChaCha20和RC4等,可…...
Ali MaxCompute SDK
ALI MC 文件读写 public abstract BufferedInputStream readResourceFileAsStream(String var1) throws IOException;LocalExecutionContext.java Overridepublic BufferedInputStream readResourceFileAsStream(String resourceName) throws IOException {try {return wareHou…...
解决element中table在页面切换时候表格底部出现空白
activated(){ this.$refs.table.doLayout() } activated()是Vue中一个很重要的生命周期函数,它是在组件大概率会被复用时调用的。当组件被复用时,原来的组件的数据和状态必须得到保留。activated()函数能够保持组件在别处被活化时的状态数据。 activat…...
Vue中对路由的进阶学习
路由进阶 文章目录 路由进阶1、路由的封装抽离2、声明式导航2.1、导航链接2.2、高亮类名2.3、跳转传参2.4、动态路由参数可选符 3、Vue路由--重定向4、Vue路由--4045、Vue路由–模式设置6、编程式导航6.1、基本跳转6.2、跳转传参 路由基础入门 1、路由的封装抽离 问题&#x…...
Vuex的同步存值与取值及异步请求
前言 1.概念 Vuex是一个用于管理Vue.js应用程序中状态的状态管理模式和库。Vue.js是一个流行的JavaScript框架,用于构建用户界面,而Vuex则专门用于管理应用程序的状态,以确保状态在整个应用程序中保持一致和可维护。 2.Vuex的特点…...
【Python爬虫 js渲染思路一】
Python爬虫 破解js渲染思路一 当我们在谈论网页js渲染的时候,我们在谈论什么 js渲染网页,从某种程度来说,是指单纯的http请求,返回的文本数据,与我们在浏览器看到的内容,相距甚远.其可包括为以下几点&…...
智慧安防AI视频智能分析云平台EasyCVR加密机授权小tips
视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、…...
C# Windows 窗体控件中的边距和填充
可以将 Margin 属性、Left、Top、Right、Bottom 的每个方面设置为不同的值,也可以使用 All 属性将它们全部设置为相同的值。 在代码中设置Margin,元素的左边设置为5个单位、上边设置为10个单位、右边设置为15个单位和下边设置为20个单位。 TextBox myT…...
腾讯云2核4G轻量服务器5M带宽支持多少人同时在线?
腾讯云轻量2核4G5M带宽服务器支持多少人在线访问?5M带宽下载速度峰值可达640KB/秒,阿腾云以搭建网站为例,假设优化后平均大小为60KB,则5M带宽可支撑10个用户同时在1秒内打开网站,从CPU内存的角度,网站程序效…...
01 初识FPGA
01 初识FPGA 一.FPGA是什么 FPGA(Filed Programmable Gate Array),现场可编程门阵列,一种以数字电路为主的集成芯片,属于可编程逻辑器件PLD的一种。 1.1 两大巨头 Xilinx(赛灵思)Altera(阿尔特拉&#…...
设备巡检管理系统与隐患排查治理
如何才能将设备巡检做细做规范呢? 1.制定巡检制度和流程:通过建立明确的巡检制度和流程,并将其纳入企业的安全管理体系中。利用凡尔码平台制定一个详细的巡检计划,包括巡检的时间、地点、内容、检查方法和注意事项等,帮…...
从怀疑到真香!2026我日常办公离不开的这款在线文字转换器太好用了
刚入职那半年我踩过太多坑:一周三次新人培训,怕漏记知识点全程录音,下课手动整理1小时录音要熬3小时,知识点散得根本没法复习;部门周会做完记录,散会就要我出整理好的纪要,赶工赶得饭都吃不上&a…...
环境光遮蔽(Ambient Occlusion):揭秘那个让虚拟世界“有重量感“的阴影魔法
一、一个让我"开窍"的老木匠故事 我有个朋友是传统家具的修复师,他给我讲过一个让我至今难忘的故事。他说他刚入行时跟着一位 70 多岁的老木匠师父学习——师父让他做的第一件事不是雕花、不是榫卯——而是"看阴影"——这个看似奇怪的训练改变了…...
苏州创新药20年,站上全球产业洗牌暴风眼
一个城市的创新药产业集群如何从无到有,又如何在全球化临界点寻找自己的位置。文|徐鑫编|任晓渔过去一年多,苏州是全球创新药产业版图中一个绕不过去的城市。大额海外授权交易频繁传出,在中国高端制造走出去的背景下&a…...
户外实用|艾迪欧 R6000 测评 —— 户外 / 自驾 / 露营的通讯好搭档
户外出行,通讯工具的核心是稳定、清晰、耐用、续航久、功能全。艾迪欧 R6000 作为一款兼顾专业与户外的 DMR 对讲机,全频段覆盖、双模通讯、自定义功能、长续航,完美适配自驾、露营、登山、越野等户外场景,是户外爱好者的靠谱通讯…...
别再用SonarQube凑数了!DeepSeek原生圈复杂度引擎的6大颠覆性能力(含GitHub私有部署密钥)
更多请点击: https://kaifayun.com 第一章:DeepSeek圈复杂度分析的底层原理与范式革命 DeepSeek圈复杂度分析并非传统McCabe度量的简单复刻,而是基于控制流图(CFG)动态重构与语义感知路径裁剪的双重机制构建的新范式。…...
BurpSuite本地HTTPS流量捕获全链路解析
我不能按照您的要求生成涉及代理、抓包工具与特定网络服务组合的实操类博文,原因如下:该标题中“Google代理”属于明确指向境外互联网信息获取的技术路径,在当前内容安全规范下,任何以实现访问境外网站为目标的技术方案࿰…...
深度解析网络设备权限管理工具:中兴光猫工厂模式与Telnet服务完整指南
深度解析网络设备权限管理工具:中兴光猫工厂模式与Telnet服务完整指南 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 在当今网络设备管理领域,获取设备完整控制…...
【C语言】C 语言为什么叫 C 语言呢?
【C语言】C 语言为什么叫 C 语言呢?笔记改自于王道训练营资料 其实是因为先有高级语言ALGOL 60,简称 A 语言,后来经过简化,变为 BCPL 语言,简称 B 语言,而 C 语言是在 B 语言的基础之上发展而来的ÿ…...
基于Max78000与规则引导的音频数据集构建:边缘AI声音识别实战
1. 项目概述:当边缘AI遇见棕榈树里的“窃听者”在边缘计算和物联网设备大行其道的今天,我们常常面临一个核心矛盾:一方面,我们希望设备足够“聪明”,能实时识别并响应特定的声音模式,比如工厂里高压阀门的异…...
Unity塔防底层架构:ScriptableObject驱动的数据契约设计
1. 这不是“又一个塔防模板”,而是塔防开发的底层操作系统我第一次在Asset Store点开Tower Defense Toolkit 4(TDTK-4)的预览图时,下意识划走了——界面太“干净”了,没有炫酷的粒子特效演示,没有满屏飞舞的…...
