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

JavaEE之线程池

前面我们了解了多个任务可以通过创建多个线程去处理,达到节约时间的效果,但是每一次的线程创建和销毁也是会消耗计算机资源的,那么我们是否可以将线程进阶一下,让消耗计算机的资源尽可能缩小呢?线程池可以达到此效果,今天我们对 《线程池》 一探究竟!

1. 何为线程池?

线程池(Thread Pool)是一种并发编程的技术,用于在应用程序启动时创建一定数量的线程,并将它们保存在线程池中,以便于任务的执行和线程的重用。当有新任务到来时,线程池会分配一个空闲线程来执行该任务,任务完成后,线程不会被销毁,而是返回线程池中,等待执行下一个任务。

2. 为什么要用线程池?

为什么要用线程池,那就得从线程池的优点来说了
优点:

  1. 重用线程:避免了频繁创建和销毁线程的开销,提高了线程的利用率。
  2. 控制并发度:可以限制并发执行的线程数量,防止系统过载。
  3. 提供线程管理和监控:方便开发人员进行线程的管理和调试。
  4. 提供任务队列:实现任务的缓冲和调度,提升系统响应速度。

3. 为什么使用线程池可以提升效率?

由于线程的频繁创建和销毁会影响计算机效率,所以我们可以减少线程的频繁创建和销毁来提高计算机效率,因为线程池可以实现这种效果,所以可以提升效率,因为线程池做的是少量创建,少量销毁,进而做到了提升效率的功能
线程池最⼤的好处就是减少每次启动、销毁线程的损耗。
从另一种方面来说,计算机分为 内核态(操作系统层面)用户态JVM层面(应用程序层),创建和销毁线程是内核态的操作

4. 线程池怎么用?

Java当中JDK给我们提供了一组针对不同使用场景的线程池实例,如下:

//1.用来处理大量短时间工作任务的线程池,如果池中没有可用的线程将创建新的线程,如果线程空闲60秒将回收并移除缓存
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//2.创建一个操作无界队列且固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//3.创建一个操作无界队列且只有一个工作线程的线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
//4.创建一个单线程执行器,可以在给定时间后执行或定期执行
ScheduledExecutorService singleThreadScheduledExecutor=Executors.newSingleThreadScheduledExecutor();
//5.创建一个指定大小的线程池,可以在给定时间后执行或定期执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
//6.创建一个指定大少(不传入参数,为当煎机器CPU核心数)的线程池,并行地处理任务
Executors.newWorkStealingPool();

说明:

  • 使用Executors.newFixedThreadPool(3)能创建出固定包含3个线程的线程池.
  • newCachedThreadPool:创建线程数目动态增长的线程池.
  • newFixedThreadPool:创建固定线程数的线程池 ,返回值类型为ExecutorService.
  • newSingleThreadExecutor: 创建只包含单个线程的线程池.
  • newSingleScheduledThreadPool:创建一个单线程执行器,设定延迟时间后执行命令,或者定期执行命令,是进阶版的Timer.
  • newScheduledThreadPool:创建一个指定大小的线程池,设定延迟时间后执行命令,或者定期执行命令.是进阶版的Timer.
  • 无界:任务队列的容量 没有限制称为无界队列
  • Executors本质上是ThreadPoolExecutor类的封装.
    在这里插入图片描述在这里插入图片描述

5. 自我实现一个线程池

思路:

  1. 首先要描述任务

通过Runnable描述任务

  1. 通过一个阻塞队列管理任务
//阻塞队列组织任务,最多处理100个任务
public static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(100);
  1. 提供一个方法向线程池提交任务
//添加任务到阻塞队列当中public void submit(Runnable runnable) throws InterruptedException {if(runnable==null){throw new IllegalAccessError("任务为空");}queue.put(runnable);}
  1. 创建多个线程,不停的扫描队列中的任务
//threadNum为初始化时,给定的线程池中含有线程的个数
public MyThreadPool(int threadNum) {if(threadNum<=0){throw new RuntimeException("线程数量必须大于0");}for (int i = 0; i < threadNum; i++) {Thread thread=new Thread(()->{//不停的扫描线程while (true) {try {//从线程中取出任务Runnable runnable = queue.take();//执行任务runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});//启动线程thread.start();}}
  1. 测试我们的线程池是否成功
public class Test {public static void main(String[] args) throws InterruptedException {//创建线程数量为3的线程池MyThreadPool myThreadPool=new MyThreadPool(3);//向线程池提交10个任务for (int i = 0; i < 10; i++) {int taskId=i+1;myThreadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println("执行任务"+taskId+", "+Thread.currentThread().getName());}});}}
}
  1. 完整的自我线程池如下:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;public class MyThreadPool {//阻塞队列组织任务,最多处理100个任务public static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(100);//添加任务到阻塞队列当中public void submit(Runnable runnable) throws InterruptedException {if(runnable==null){throw new IllegalAccessError("任务为空");}queue.put(runnable);}public MyThreadPool(int threadNum) {if(threadNum<=0){throw new RuntimeException("线程数量必须大于0");}for (int i = 0; i < threadNum; i++) {Thread thread=new Thread(()->{//不停的扫描线程while (true) {try {//从线程中取出任务Runnable runnable = queue.take();//执行任务runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});//启动线程thread.start();}}
}

6. 创建系统自带的线程池

在这里插入图片描述

执行流程:

  1. 添加任务,核心线程从队列中取任务去执行
  2. 核心线程都在工作时,再添加的任务会进入到阻塞队列
  3. 阻塞队列满了后,会创建临时线程
  4. 阻塞队列满了并且临时线程达到最大,执行拒绝策略
    一次性创建最大的线程数(根据机器的配置,比如CPU核数)

图解:

在这里插入图片描述

说明:

  • corePoolSize: 核心线程的数量.(类似于正式员⼯,⼀旦录⽤,永不辞退)
  • maximumPoolSize:线程池中最大的线程数=核心线程+临时线程的数目.(类似于临时⼯:⼀段时间不⼲活,就被辞退)
  • keepAliveTime:临时线程存活的时间
  • unit:临时线程存活的时间单位,是秒,分钟,还是其他值
  • workQueue:组织(保存)任务的队列
  • threadFactory: 创建线程的工厂,参与具体的创建线程⼯作.通过不同线程工厂创建出的线程相当于对一些属性进行了不同的初始化设置
  • RejectedExecutionHandler: 拒绝策略,如果任务量超出线程池的负荷了接下来怎么处理
    在这里插入图片描述

接下来我们探讨一下这四种拒绝策略:

1. AbortPolicy(): 超过负荷,直接抛出异常.

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestAbortPolicy {public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor reject1 =new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject1.submit(() -> {System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

在这里插入图片描述

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接拒绝了,并抛出异常,我不做!!

2. CallerRunsPolicy():返回给调⽤者负责处理多出来的任务.

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestCallerRunsPolicy {public static void main(String[] args) {ThreadPoolExecutor reject2=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject2.submit(()->{System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

在这里插入图片描述

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接拒绝了,老师就自己去做了,保证了任务至少完成了。

3. DiscardOldestPolicy():丢弃队列中最⽼的任务.

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestDiscardOldestPolicy {public static void main(String[] args) {ThreadPoolExecutor reject2=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.DiscardOldestPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject2.submit(()->{System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

在这里插入图片描述

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接退出游戏(不处理最老的任务),去完成老师交给我的任务。

4. DiscardPolicy():丢弃新来的任务.

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TestDiscardPolicy {public static void main(String[] args) {ThreadPoolExecutor reject2=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.DiscardPolicy());for (int i = 0; i < 100; i++) {int taskId = i + 1;reject2.submit(()->{System.out.println("执行任务:" + taskId + ", " + Thread.currentThread().getName());});}}
}

在这里插入图片描述

举个例子: 现在我在和我的女友玩游戏,老师让我帮他做一项报告,我直接拒绝了,老师也不做,日后可能忘记了该任务,再也找不回来。

总结: 在实际的开发过程中,我们要根据实际的业务场景选择不同的拒绝策略!!!

以上就是线程池的基本知识了,希望对你有帮助,谢谢!!

相关文章:

JavaEE之线程池

前面我们了解了多个任务可以通过创建多个线程去处理&#xff0c;达到节约时间的效果&#xff0c;但是每一次的线程创建和销毁也是会消耗计算机资源的&#xff0c;那么我们是否可以将线程进阶一下&#xff0c;让消耗计算机的资源尽可能缩小呢&#xff1f;线程池可以达到此效果&a…...

java 中 main 方法使用 KafkaConsumer 拉取 kafka 消息如何禁止输出 debug 日志

pom 依赖&#xff1a; <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><version>2.5.14.RELEASE</version> </dependency> 或者 <dependency><groupId>org.ap…...

【后端面试总结】Golang可能的内存泄漏场景及应对策略

Golang可能的内存泄漏场景及应对策略 一、引言 Golang作为一种高性能、并发友好的编程语言&#xff0c;其内置的垃圾回收机制极大地简化了内存管理。然而&#xff0c;这并不意味着开发者可以完全忽视内存泄漏问题。在实际开发中&#xff0c;由于不当的资源管理、循环引用、以…...

Java 反射机制详解

在 Java 编程世界中&#xff0c;反射机制犹如一把神奇的钥匙&#xff0c;它能够打开许多隐藏在代码深处的 “大门”&#xff0c;让开发者突破常规的限制&#xff0c;实现一些极具灵活性的功能。今天&#xff0c;就跟随我一同深入探究 Java 反射机制的奥秘。 一、什么是反射 反…...

【k8s】scc权限 restricted、anyuid、privileged

文章目录 概述1. 内置的scc2. OpenShift如何确定pod的scc2.1 Pod未带SCC标签的情况2.2. Pod带有SCC标签的情况 参考 概述 在OpenShift&#xff08;后文简称OCP&#xff09;中&#xff0c;很早就一个概念&#xff1a;Security Context Constraints &#xff0c;简称SCC&#xf…...

2025华数杯国际赛A题完整论文讲解(含每一问python代码+数据+可视化图)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2025“华数杯”国际大学生数学建模竞赛A题Can He Swim Faster的完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文…...

ThreadLocal 的使用场景

在现代电商平台中&#xff0c;ThreadLocal 常用于以下场景&#xff0c;特别是与线程隔离相关的业务中&#xff0c;以提高性能和简化上下文传递。 1. 用户上下文信息管理 场景&#xff1a;在用户发起的每次请求中&#xff0c;需要携带用户 ID、角色、权限等信息&#xff0c;而这…...

后端开发 Springboot整合Redis Spring Data Redis 模板

目录 redis 配置 RedisConfig 类 完整代码 代码讲解 1. 类定义和注解 2. 定义 RedisTemplate Bean 3. 配置 JSON 序列化 4. 配置 Redis 的 key 和 value 序列化方式 5. 完成配置并返回 RedisTemplate 总结 redis 服务接口实现类 类级别 注入 RedisTemplate 常用 Re…...

代码随想录算法训练营第 4 天(链表 2)| 24. 两两交换链表中的节点19.删除链表的倒数第N个节点 -

一、24. 两两交换链表中的节点 题目&#xff1a;24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 视频&#xff1a;帮你把链表细节学清楚&#xff01; | LeetCode&#xff1a;24. 两两交换链表中的节点_哔哩哔哩_bilibili 讲解&#xff1a;代码随想录 dummy-…...

【RDMA学习笔记】1:RDMA(Remote Direct Memory Access)介绍

从帝国理工的PPT学习。 什么是RDMA Remote Direct Memory Access&#xff0c;也就是Remote的DMA&#xff0c;是一种硬件机制&#xff0c;能直接访问远端结点的内存&#xff0c;而不需要处理器介入。 其中&#xff1a; Remote&#xff1a;跨node进行数据传输Direct&#xff…...

网络安全常见的35个安全框架及模型

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 01、概述 网络安全专业机构制定的一套标准、准则和程序&#xff0c;旨在帮助组织了解和管理面临的网络安全风险。优秀的安全框架及模型应该为用户提供一种可靠方法&#xff0c;帮助其实现网络安全建设…...

Elasticsearch介绍及使用

Elasticsearch 是一款基于 Lucene 库构建的开源、分布式、RESTful 风格的搜索引擎和分析引擎&#xff0c;具有强大的全文搜索、数据分析、机器学习等功能&#xff0c;广泛应用于日志分析、实时数据分析、全文检索等场景。 核心概念 索引&#xff08;Index&#xff09;&#xf…...

Leetocde516. 最长回文子序列 动态规划

原题链接&#xff1a;Leetocde516. 最长回文子序列 class Solution { public:int longestPalindromeSubseq(string s) {int n s.size();vector<vector<int>> dp(n, vector<int>(n, 1));for (int i 0; i < n; i) {dp[i][i] 1;if (i 1 < n &&…...

iOS 逆向学习 - Inter-Process Communication:进程间通信

iOS 逆向学习 - Inter-Process Communication&#xff1a;进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…...

高级生化大纲

一&#xff0c;蛋白质化学&#xff1a; 蛋白质分离是生物化学和分子生物学研究中的一项基本技术&#xff0c;用于根据蛋白质的物理和化学特性将其从混合物中分离出来。 1. 离心分离法 离心分离法利用离心力来分离不同质量或密度的颗粒和分子。 差速离心&#xff1a;通过逐…...

YARN WebUI 服务

一、WebUI 使用 与HDFS一样&#xff0c;YARN也提供了一个WebUI服务&#xff0c;可以使用YARN Web用户界面监视群集、队列、应用程序、服务、流活动和节点信息。还可以查看集群详细配置的信息&#xff0c;检查各种应用程序和服务的日志。 1.1 首页 浏览器输入http://node2.itc…...

【Unity3D】利用IJob、Burst优化处理切割物体

参考文章&#xff1a; 【Unity】切割网格 【Unity3D】ECS入门学习&#xff08;一&#xff09;导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习&#xff08;十二&#xff09;IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...

【大前端】Vue3 工程化项目使用详解

目录 一、前言 二、前置准备 2.1 环境准备 2.1.1 create-vue功能 2.1.2 nodejs环境 2.1.3 配置nodejs的环境变量 2.1.4 更换安装包的源 三、工程化项目创建与启动过程 3.1 创建工程化项目 3.2 项目初始化 3.3 项目启动 3.4 核心文件说明 四、VUE两种不同的API风格 …...

基于文件系统分布式锁原理

分布式锁&#xff1a;在一个公共的存储服务上打上一个标记&#xff0c;如Redis的setnx命令&#xff0c;是先到先得方式获得锁&#xff0c;ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...

简历整理YH

一&#xff0c;订单中心 1&#xff0c;调拨单 融通(Rocketmq)-订单中心&#xff1a;ECC_BMS123(已出单)&#xff0c;125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2&#xff0c;销售单 sap&#xff08;FTP&#xff09;-订单中心&#xff0c;下发1002,1003,…...

Kotlin 协程基础三 —— 结构化并发(二)

Kotlin 协程基础系列&#xff1a; Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发&#xff08;一&#xff09; Kotlin 协程基础三 —— 结构化并发&#xff08;二&#xff09; Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...

微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果

有一个需求需要在微信小程序上实现一个长按时进行语音录制&#xff0c;录制时间最大为60秒&#xff0c;录制完成后&#xff0c;可点击播放&#xff0c;播放时再次点击停止播放&#xff0c;可以反复录制&#xff0c;新录制的语音把之前的语音覆盖掉&#xff0c;也可以主动长按删…...

校园跑腿小程序---轮播图,导航栏开发

hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生…...

详细全面讲解C++中重载、隐藏、覆盖的区别

文章目录 总结1、重载示例代码特点1. 模板函数和非模板函数重载2. 重载示例与调用规则示例代码调用规则解释3. 特殊情况与注意事项二义性问题 函数特化与重载的交互 2. 函数隐藏&#xff08;Function Hiding&#xff09;概念示例代码特点 3. 函数覆盖&#xff08;重写&#xff…...

一文读懂单片机的串口

目录 串口通信的基本概念 串口通信的关键参数 单片机串口的硬件连接 单片机串口的工作原理 数据发送过程 数据接收过程 单片机串口的编程实现 以51单片机为例 硬件连接 初始化串口 发送数据 接收数据 串口中断服务函数 代码示例 单片机串口的应用实例 单片机与…...

HTML5 网站模板

HTML5 网站模板 参考 HTML5 Website Templates...

mybatis分页插件:PageHelper、mybatis-plus-jsqlparser(解决SQL_SERVER2005连接分页查询OFFSET问题)

文章目录 引言I PageHelper坐标II mybatis-plus-jsqlparser坐标Spring Boot 添加分页插件自定义 Mapper 方法中使用分页注意事项解决SQL_SERVER2005连接分页查询OFFSET问题知识扩展MyBatis-Plus 框架结构mybatis-plus-jsqlparser的 Page 类引言 PageHelper import com.github.p…...

uniapp中rpx和upx的区别

在 UniApp 中&#xff0c;rpx 和 upx 是两种不同的单位&#xff0c;它们的主要区别在于适用的场景和计算方式。 ### rpx&#xff08;Responsive Pixel&#xff09; - **适用场景**&#xff1a;rpx 是一种响应式单位&#xff0c;主要用于小程序和移动端的布局。 - **计算方式**…...

什么是卷积网络中的平移不变性?平移shft在数据增强中的意义

今天来介绍一下数据增强中的平移shft操作和卷积网络中的平移不变性。 1、什么是平移 Shift 平移是指在数据增强&#xff08;data augmentation&#xff09;过程中&#xff0c;通过对输入图像或目标进行位置偏移&#xff08;平移&#xff09;&#xff0c;让目标在图像中呈现出…...

java.net.SocketException: Connection reset 异常原因分析和解决方法

导致此异常的原因&#xff0c;总结下来有三种情况&#xff1a; 一、服务器端偶尔出现了异常&#xff0c;导致连接关闭 解决方法&#xff1a; 采用出错重试机制 二、 服务器端和客户端使用的连接方式不一致 解决方法&#xff1a; 服务器端和客户端使用相同的连接方式&#xff…...

wordpress 交互页面/线上平台推广方式

定义 2020疫情&#xff0c;让国内企业就全面接受了“在线办公、在家办公”的理念&#xff0c;并付诸实践。即使是最为传统的中小学公立学校&#xff0c;也由袖手旁观转为积极参与。腾讯、阿里、华为、电信、移动都相继推出了免费的远程办公和视频会议系统&#xff0c;这些系统都…...

websocket wordpress/网络推广优化平台

前言 在大型系统中&#xff0c;为了减少数据库压力通常会引入缓存机制&#xff0c;一旦引入缓存又很容易造成缓存和数据库数据不一致&#xff0c;导致用户看到的是旧数据。 为了减少数据不一致的情况&#xff0c;更新缓存和数据库的机制显得尤为重要&#xff0c;接下来带领大…...

室内设计工作室排名/电商运营seo

有时候导入一些module时&#xff0c;会出现以下问题 Android dependency com.android.support:support-v4 has different version for the compile (23.3.0) and runtime (25.4.0) classpath. You should manually set the same version via DependencyResolution 1这是因为mod…...

北京大型网站开发/哪里能搜索引擎优化

​估计看到这篇文章的朋友&#xff0c;都是有使用过Smartbi制作数据可视化图表的。但是不是制作过程跟制作效果并没有让自己那么满意。使用过程也经常遇到一些问题解决不了&#xff1f;那是因为你使用的方法不对。你是否在使用Smartbi制作数据可视化图表前&#xff0c;有先学习…...

家居网站建设/app如何推广

Java中main方法的格式讲解 class MainDemo {public static void main(String[] args){} } 组成使用说明public公共的&#xff0c;访问权限是最大的&#xff0c;由于 main 方法是被 jvm 调用&#xff0c;所以权限要够大static静态的&#xff0c;不需要创建对象&#xff0c;通过…...

做网站需要去哪里备案/做灰色词seo靠谱

Linux虚拟网桥的特点&#xff1a;&#xff08;docker0&#xff09;1、可以设置IP地址2、相当于拥有一个隐藏的虚拟网卡安装网桥管理工具&#xff1a;[rooti-wx7sdofs ~]# yum install bridge-utils修改docker0地址&#xff1a;(有特定需求时使用)$ ifconfig docker0 192.168.20…...