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

【JAVA多线程】线程池概论

目录

1.概述

2.ThreadPoolExector

2.1.参数

2.2.新任务提交流程

2.3.拒绝策略

2.4.代码示例


1.概述

线程池的核心:

线程池的实现原理是个标准的生产消费者模型,调用方不停向线程池中写数据,线程池中的线程组不停从队列中取任务。

实现线程池需要考虑的几个核心因素:

  • 队列的长度

  • 队列满后,后面来的线程如何处理

队列的长度:

用来存线程这个队列的长度太小了可能会不够用,要是没有限制又可能导致机器的物理内存耗尽,所以最好的方式就是给这个队列一个初始化的长度,然后允许这个队列动态扩容。

队列满后,后面来的任务如何处理:

队列满了之后新来的任务如何处理?也就是拒绝策略,关于这个拒绝策略,是直接拒绝丢弃掉?还是把队列中的老任务丢弃掉给它让位置?还是说不走线程池,直接新开一条线程来执行?

继承体系:

可以看到顶级父接口提供了规范标准,真正干活儿的实现类只有ThreadPoolExcutor和ScheduleThreadPoolExecutor。

本文主要以ThreadPoolExcutor为切入聊一下线程池的核心概念,由于ScheduleThreadPoolExecutor主要是用来做延迟任务和周期任务的,以它为切入来聊线程池的核心概念并不是那么合适,后面会有文章专门聊一聊JDK基于线程池打造的一整套延迟任务、周期任务、异步任务等,这些任务调度体系。

2.ThreadPoolExector

2.1.参数

public class ThreadPoolExecutor extends AbstractExecutorService{private final AtomicInteger ctl;//状态变量private final BlockingQueue<Runnable> workQueue;//任务队列private final ReentrantLock mainLock;//用于保证线程池中各变量之间的互斥private final HashSet<ThreadPoolExecutor.Worker> workers;//线程组
}
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{final Thread thread;//被封装的线程Runnable firstTask;//worker收到的第一个任务volatile long completedTasks;//worker执行完毕的任务数
}

线程池的核心参数为

  • corePoolSize:在线程池中始终维护的线程个数.

  • maxPoolSize:在corePooSize已满、队列也满的情况下,扩 充线程至此值。

  • keepAliveTime/TimeUnit:maxPoolSize 中的空闲线程,销 毁所需要的时间,总线程数收缩回corePoolSize。

  • blockingQueue:线程池所用的队列类型。

  • threadFactory:线程创建工厂,可以自定义,也有一个默 认的。

  • RejectedExecutionHandler:corePoolSize 已满,队列已 满,maxPoolSize 已满,最后的拒绝策略。

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.acc = System.getSecurityManager() == null ?null :AccessController.getContext();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

2.2.新任务提交流程

入口在ThreadPoolExector.execute(Runnable command)

public void execute(Runnable command) {if (command == null)throw new NullPointerException();
​int c = ctl.get();//如果当前线程组中的线程数量小于核心线程数,直接开一个新线程来执行该任务if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}//如果当前线程组中的线程数量大于等于核心线程数,将该任务放入队列中if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}//放入队列失败,再尝试新开一个线程来执行该任务else if (!addWorker(command, false))//这时候再失败意味着线程组数量已经大于maxPoolSize且任务队列已满,直接执行拒绝策略reject(command);}

2.3.拒绝策略

ThreadPoolExector一共提供了四种拒绝策略:

  • AbortPolicy,默认拒绝策略,直接抛出异常。

  • CallerRunsPolicy,让任务在调用者的线程中执行,线程池不对任务做处理。

  • DiscardPolicy,线程池直接把任务丢弃掉,就当什么都没有发生。

  • DiscardOldestPolicy,把队列中最老的任务删掉,将新任务放入队列。

2.4.代码示例

在使用线程池的时候并不需要我们手动去创建,JDK中有工具类来帮我们创建各种线程池,这个工具类只是包了一层,其底层还是创建的我们上面聊的这些线程池的实现类,以下是代码示例:

import java.util.concurrent.*;public class ThreadPoolExamples {public static void main(String[] args) throws InterruptedException {// 固定大小的线程池示例fixedThreadPoolExample();// 单线程线程池示例singleThreadExecutorExample();// 缓存线程池示例cachedThreadPoolExample();// 定时线程池示例scheduledThreadPoolExample();}/*** 创建一个固定大小的线程池,该线程池中的线程数量固定,不会因为任务的增加而增加新的线程。*/private static void fixedThreadPoolExample() {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); // 创建一个包含5个线程的线程池for (int i = 0; i < 10; i++) {final int taskId = i;fixedThreadPool.execute(() -> {System.out.println("FixedThreadPool: Task ID " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟耗时操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("FixedThreadPool: Task ID " + taskId + " finished by " + Thread.currentThread().getName());});}fixedThreadPool.shutdown(); // 关闭线程池try {fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}}/*** 创建一个单线程线程池,所有的任务都将在同一个线程中依次执行。*/private static void singleThreadExecutorExample() {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); // 创建一个单线程的线程池for (int i = 0; i < 10; i++) {final int taskId = i;singleThreadExecutor.execute(() -> {System.out.println("SingleThreadExecutor: Task ID " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟耗时操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("SingleThreadExecutor: Task ID " + taskId + " finished by " + Thread.currentThread().getName());});}singleThreadExecutor.shutdown(); // 关闭线程池try {singleThreadExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}}/*** 创建一个缓存线程池,该线程池会根据需要创建新线程,但会在线程闲置后回收线程。*/private static void cachedThreadPoolExample() {ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); // 创建一个缓存线程池for (int i = 0; i < 10; i++) {final int taskId = i;cachedThreadPool.execute(() -> {System.out.println("CachedThreadPool: Task ID " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟耗时操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("CachedThreadPool: Task ID " + taskId + " finished by " + Thread.currentThread().getName());});}cachedThreadPool.shutdown(); // 关闭线程池try {cachedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}}/*** 创建一个定时线程池,可以安排任务在指定时间执行,或定期执行任务。*/private static void scheduledThreadPoolExample() {ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); // 创建一个包含5个线程的定时线程池Runnable task = () -> System.out.println("ScheduledThreadPool: Task executed at: " + System.currentTimeMillis());// 安排在1秒后执行一次,然后每隔2秒重复执行scheduledThreadPool.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);try {Thread.sleep(10000); // 主线程休眠10秒,以便观察任务执行情况} catch (InterruptedException e) {e.printStackTrace();}scheduledThreadPool.shutdown(); // 关闭线程池}
}

相关文章:

【JAVA多线程】线程池概论

目录 1.概述 2.ThreadPoolExector 2.1.参数 2.2.新任务提交流程 2.3.拒绝策略 2.4.代码示例 1.概述 线程池的核心&#xff1a; 线程池的实现原理是个标准的生产消费者模型&#xff0c;调用方不停向线程池中写数据&#xff0c;线程池中的线程组不停从队列中取任务。 实现…...

java双亲委派机制

Java中的双亲委派机制&#xff08;Parent Delegation Model&#xff09;是一种类加载机制&#xff0c;它确保了类加载的安全性和一致性。该机制规定了类加载器在加载类时的顺序和方式&#xff0c;从而避免了重复加载和类冲突问题。 以下是一个简单的自定义类加载器的示例&#…...

记录第一次使用air热更新golang项目

下载 go install github.com/cosmtrek/airlatest 下载时提示&#xff1a; module declares its path as: github.com/air-verse/air but was required as: github.com/cosmtrek/air 此时&#xff0c;需要在go.mod中加上这么一句&#xff1a; replace github.com/cosmtrek/air &…...

Leetcode 3213. Construct String with Minimum Cost

Leetcode 3213. Construct String with Minimum Cost 1. 解题思路2. 代码实现 题目链接&#xff1a;3213. Construct String with Minimum Cost 1. 解题思路 这一题的话思路上还是比较直接的&#xff0c;就是一个trie树加一个动态规划&#xff0c;通过trie树来快速寻找每一个…...

python操作SQLite3数据库进行增删改查

python操作SQLite3数据库进行增删改查 1、创建SQLite3数据库 可以通过Navicat图形化软件来创建: 2、创建表 利用Navicat图形化软件来创建: 存储在 SQLite 数据库中的每个值(或是由数据库引擎所操作的值)都有一个以下的存储类型: NULL. 值是空值。 INTEGER. 值是有符…...

【电控笔记6.7】非最小相位系统

全通滤波器 [...

Day05-04-持续集成总结

Day05-04-持续集成总结 1. 持续集成2. 代码上线目标项目 1. 持续集成 git 基本使用, 拉取代码,上传代码,分支操作,tag标签 gitlab 用户 用户组 项目 , 备份,https,优化. jenkins 工具平台,运维核心, 自由风格工程,maven风格项目,流水线项目, 流水线(pipeline) mavenpom.xmlta…...

PyQt5动态热力图清空画布关闭ColorBar

PyQt5生成正弦波动态热力图清空画布关闭ColorBar 1、简介 生成随机正弦波,使用pyqtgraph展示出来,并且使用热力图展示不同频率的正弦波,使用不同的画布颜色显示热力图的变化。 使用python3.8 导入库: pip install matplotlib==3.7.5 pip install numpy==1.24.4 pip in…...

python爬虫入门(一)之HTTP请求和响应

一、爬虫的三个步骤&#xff08;要学习的内容&#xff09; 1、获取网页内容 &#xff08;HTTP请求、Requests库&#xff09; 2、解析网页内容 &#xff08;HTML网页结构、Beautiful Soup库&#xff09; 3、存储或分析数据 b站学习链接&#xff1a; 【【Python爬虫】爆肝两…...

华为OD机考题(HJ41 称砝码)

前言 经过前期的数据结构和算法学习&#xff0c;开始以OD机考题作为练习题&#xff0c;继续加强下熟练程度。有需要的可以同步练习下。 描述 现有n种砝码&#xff0c;重量互不相等&#xff0c;分别为 m1,m2,m3…mn &#xff1b; 每种砝码对应的数量为 x1,x2,x3...xn 。现在要…...

Qt涂鸦板

Qt版本&#xff1a;Qt6 具体代码&#xff1a; 头文件 dialog.h #ifndef DIALOG_H #define DIALOG_H#include <QDialog>QT_BEGIN_NAMESPACE namespace Ui { class Dialog; } QT_END_NAMESPACEclass Dialog : public QDialog {Q_OBJECTpublic:Dialog(QWidget *parent n…...

C++_03

1、构造函数 1.1 什么是构造函数 类的构造函数是类的一种特殊的成员函数&#xff0c;它会在每次创建类的新对象时执行。 每次构造的是构造成员变量的初始化值&#xff0c;内存空间等。 构造函数的名称与类的名称是完全相同的&#xff0c;并且不会返回任何类型&#xff0c;也不…...

强化学习中的Double DQN、Dueling DQN和PER DQN算法详解及实战

1. 深度Q网络&#xff08;DQN&#xff09;回顾 DQN通过神经网络近似状态-动作值函数&#xff08;Q函数&#xff09;&#xff0c;在训练过程中使用经验回放&#xff08;Experience Replay&#xff09;和固定目标网络&#xff08;Fixed Target Network&#xff09;来稳定训练过程…...

前端八股文 说一说样式优先级的规则是什么?

标准的回答 CSS样式的优先级应该分成四大类 第一类 !important&#xff1a; &#x1f604;无论引入方式是什么&#xff0c;选择器是什么&#xff0c;它的优先级都是最高的。 第二类 引入方式&#xff1a; &#x1f604;行内样式的优先级要高于嵌入和外链&#xff0c;嵌入和外链…...

洞察国内 AI 绘画行业的璀璨前景

在科技的浪潮中&#xff0c;AI 绘画如同一颗璀璨的新星&#xff0c;正在国内的艺术与技术领域绽放出耀眼的光芒。 近年来&#xff0c;国内 AI 绘画行业发展迅猛&#xff0c;展现出巨大的潜力。随着人工智能技术的不断突破&#xff0c;AI 绘画算法日益精进&#xff0c;能够生成…...

socket编程

文章目录 套接字网路字节序列TCP和UDP套接字 本文章主要介绍Linux下套接字的相关接口&#xff0c;和一些基础知识。 套接字 所有网络通信的行为本质都是进程间进行通信&#xff0c;网络通信也是进程间通信&#xff0c;只不过是不同主机上的两个进程之间的通信。网络通信对于双…...

python自动移除excel文件密码(升级v2版本)

欢迎查看第一版 https://blog.csdn.net/weixin_45631815/article/details/140013476?spm1001.2014.3001.5502 一功能改进 此版本主要改进功能有以下: 直接可以调用函数实现可以尝试多个密码没有加密的文件进行保存,可以按实际业务进行改进.思路来源:java 面向对象设计模式.…...

深入MOJO编程语言的单元测试世界

引言 在软件开发的历程中&#xff0c;单元测试扮演着至关重要的角色。单元测试不仅帮助开发者确保代码的每个部分都按预期工作&#xff0c;而且也是代码质量和维护性的关键保障。本文将引导读者了解如何在MOJO这一假想编程语言中编写单元测试&#xff0c;尽管MOJO并非真实存在…...

Canvas:掌握颜色线条与图像文字设置

想象一下&#xff0c;用几行代码就能创造出如此逼真的图像和动画&#xff0c;仿佛将艺术与科技完美融合&#xff0c;前端开发的Canvas技术正是这个数字化时代中最具魔力的一环&#xff0c;它不仅仅是网页的一部分&#xff0c;更是一个无限创意的画布&#xff0c;一个让你的想象…...

打包导入pyzbar的脚本时的注意事项

目录 前言问题问题的出现解决 总结 本文由Jzwalliser原创&#xff0c;发布在CSDN平台上&#xff0c;遵循CC 4.0 BY-SA协议。 因此&#xff0c;若需转载/引用本文&#xff0c;请注明作者并附原文链接&#xff0c;且禁止删除/修改本段文字。 违者必究&#xff0c;谢谢配合。 个人…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...