JAVA 线程池,及7大参数,4大拒绝策略详解

为什么要使用线程池

线程的生命周期:运行、就绪、运行、阻塞、死亡

下面是一个简单的创建多线程的方法。注意:工作中不可取

在这里插入图片描述

创建线程的时候,我们避不开线程的生命周期。上面的方法虽然可以创建多线程,但是创建完成后,我们可能还需要进行销毁,如果中间出现异常就可能会导致回收不了,或者在线程里面又创建一个线程,而线程切换也需要消耗时间和空间,就会导致线程管理起来很困难。

为了解决找个问题,我们参考一下阿里的做法:通过线程池的方式来管理线程。当然如果你有其他更好的管理线程的方式也可以。

在这里插入图片描述

JDK 常用的线程池

线程池作为一种池化技术,实现起来比较困难,但是 JDK下面的 java.util.concurrent 包提供了几种类型的线程池,主要通过 Executors 类中的静态工厂方法来创建。
在这里插入图片描述

下面简单列出两种线程池的使用示例

public static void main(String[] args) {System.out.println("--- 创建唯一的线程 ---");ExecutorService executorService01 = Executors.newSingleThreadExecutor();executorService01.execute(() -> {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);try {Thread.sleep(200);} catch (InterruptedException e) {throw new RuntimeException(e);}}});System.out.println("--- Fixed 线程数5---");ExecutorService executorService02 = Executors.newFixedThreadPool(5);for (int t = 0; t < 10; t++) {executorService02.execute(() -> {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);try {Thread.sleep(200);} catch (InterruptedException e) {throw new RuntimeException(e);}}});}
}

上面代码运行,我们发现,线程创建后不会自动被销毁,而且线程可以被复用,可以减少每次创建线程消耗的时间和资源的浪费。

但是我们看阿里的开发手册上不允许使用 Executors 来创建,而需要使用 ThreadPoolExecutor 类来创建,如下图:
在这里插入图片描述
我们看一下,刚刚使用的两种线程池的源码,发现其实都是由 ThreadPoolExecutor 类创建的线程。

在这里插入图片描述
在这里插入图片描述

所以后续我们就可以使用 ThreadPoolExecutor 类来自定义线程池。

为什么阿里不允许使用 Executors 来创建线程池呢?我们可以在文档上看到
在这里插入图片描述
我们按照手册上写的看一下源码。

在这里插入图片描述
我们看到它是使用阻塞式队列来存线程,以链表的方式。链表理论上是没有容量限制的,但是其实是有限制的,最大的容量就是 Integer.MAX_VALUE(23亿左右),理论上这个queue 可以放 23亿左右,因为没有限制长度,所以可能造成这个 queue 里面存放很多线程,从而造成 OOM 错误。
在这里插入图片描述
为了避免上面的问题,我们一般自定义线程池。

自定义线程池

线程池结构图

在这里插入图片描述
如上图所示,执行顺序为:当提交任务数大于核心线程数时,会优先将任务放到阻塞队列中。当阻塞队列饱和时,会扩充线程池中的线程数,直到达到最大线程数。当任务数超出最大线程数时,就会触发线程池的拒绝策略。

核心参数

序列参数名含义
1corePoolSize核心线程数
2maximumPoolSize最大线程数(必须大于核心线程数)
3keepAliveTime空闲线程的存活时间
4Unit时间单位
5workQueue用于存放任务的队列
6threadFactory线程工厂、用来创建新线程
7handler处理被拒绝的任务
  1. 核心线程数(corePoolSize):指线程池中保持活动状态的最少线程数,即使在空闲时也不会被回收。当有新的任务提交时,如果当前活动线程数小于核心线程数,则会创建新的线程来处理任务。

  2. 最大线程数(maximumPoolSize):线程池中允许存在的最大线程数,当任务队列已满且当前活动线程数小于最大线程数时,线程池会创建新的线程,直到达到最大线程数。

  3. 空闲线程存活时间(keepAliveTime):指空闲线程在被回收之前可以等待新任务的最长时间。当线程池中的线程数量超过核心线程数,并且处于空闲状态时,这些多余的线程在超过指定时间后会被回收销毁。

  4. 时间单位(unit):空闲线程存活时间的单位,可以是秒、毫秒、分钟等。

  5. 任务队列(workQueue):用于存放等待执行任务的阻塞队列。可以选择不同的队列类型来实现不同的调度策略。当线程池中的线程都在工作且任务队列已满时,新的任务会被拒绝执行。

  6. 线程工厂(threadFactory):用于创建新线程的工厂,可以自定义线程的名称、优先级等属性。

  7. 拒绝策略(rejectedExecutionHandler):当线程池已满并且任务无法执行时的处理策略,如何处理新提交的任务。

拒绝策略

拒绝策略在线程池已满且无法接受新的任务时会被触发:

  1. 线程池的线程数量已经达到了最大线程数,无法再创建新的线程来执行任务。
  2. 线程池中的任务队列已满,无法接受新的任务。

当同时满足上面两个条件时,拒绝策略会被触发,根据所选的拒绝策略进行相应的处理。

需要注意的是,拒绝策略的触发并不代表任务一定会被丢弃或忽视,而是指当线程池已达到最大容量且任务队列已满时,新提交的任务无法被正常处理,因此需要通过拒绝策略来决定如何处理这些无法接受的任务。

  1. AbortPolicy (中止策略)
    默认的拒绝策略,当线程池已满且任务队列也已满时,会抛出 RejectedExecutionException 异常来拒绝新提交的任务。
    在这里插入图片描述

  2. CallerRunsPolicy (调用者运行策略)
    当线程池已满且任务队列也已满时,新提交的任务会由提交任务的线程来执行(调用线程自己执行),而不会开启新的线程。

  3. DiscardPolicy (丢弃策略)
    当线程池已满且任务队列也已满时,直接丢弃新提交的任务,不做任何处理。

  4. DiscardOldestPolicy (丢弃最老策略)
    当线程池已满且任务队列也已满时,丢弃最早提交的任务,然后尝试执行新提交的任务。

自定义线程池示例代码

import java.util.concurrent.*;public class CustomerThreadPool {static class MyAbortPolicy implements RejectedExecutionHandler {/*** Creates an {@code AbortPolicy}.*/public MyAbortPolicy() { }/*** Always throws RejectedExecutionException.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task* @throws RejectedExecutionException always*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException("任务 " + r.toString() +" 拒绝 from " +e.toString());}}public static void main(String[] args){int corePoolSize = 4;int maximumPoolSize = 10;long keepAliveTime = 500;TimeUnit unit = TimeUnit.MILLISECONDS;BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10);RejectedExecutionHandler handler = null;ThreadPoolExecutor myPool = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,r->{System.out.println("创建线程:"+r);return new Thread(r);},new MyAbortPolicy());for (int t=0;t<20;t++) {myPool.execute(()->{for (int i=0;i<10;i++) {System.out.println(Thread.currentThread().getName()+":"+i);try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}});}}
}

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

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

相关文章

Ubuntu 环境安装 Kafka、配置运行测试 Kafka 流程笔记

Kafka 介绍 Kafka 是一个由 Apache 软件基金会开发的开源流式处理平台。它被设计用于处理大规模数据流&#xff0c;提供高可靠性、高吞吐量和低延迟的消息传递系统。Kafka 可以用于构建实时数据管道和流式应用程序&#xff0c;让不同应用、系统或者数据源之间能够高效地进行数…

老师怎样避免精神内耗?

在老师的职业生涯中&#xff0c;遇到的挑战和压力可能会导致精神内耗&#xff0c;这会影响到心理和身体健康&#xff0c;更进一步影响到工作成果和个人生活。为了避免精神内耗&#xff0c;老师可以尝试以下方法&#xff1a; 1. 建立正面的心态&#xff1a;老师需要学会积极思考…

卡码网语言基础课 | 19. 洗盘子

目录 一、 栈的基本概念 二、 栈的操作 2.1 引入头文件 2.2 创建栈 2.3 栈的基本认识 三、 解答 通过本次练习&#xff0c;将学习到以下 C知识点&#xff1a; 栈的基本概念&#xff08;空栈、栈顶、栈底&#xff09;和特点&#xff08;先入后出&#xff09;入栈、出栈、获取…

PostGIS学习教程十:空间索引

PostGIS学习教程十&#xff1a;空间索引 回想一下&#xff0c;空间索引是空间数据库的三个关键特性之一。空间索引使得使用空间数据库存储大型数据集成为可能。在没有空间索引的情况下&#xff0c;对要素的任何搜索都需要对数据库中的每条记录进行"顺序扫描"。索引通…

设计模式——七大设计原则

设计模式——七大设计原则 1、单一职责原则&#xff08;SRP&#xff09;2、开放封闭原则&#xff08;OCP&#xff09;3、依赖倒转原则&#xff08;DIP&#xff09;4、里氏替换原则 (LSP)5、接口隔离原则 (ISP)6、合成/聚合复用原则 (CARP)7、迪米特法则 (LoD) 了解 设计模式 的…

如何使用llm 制作多模态

首先将任何非字符的序列信息使用特殊n个token 编码。 具体编码方法以图像为例子说明&#xff1a; 将固定尺寸图像如256256 的图像分割为1616 的子图像块。 将已知的所有图像数据都分割后进行str将其看做是一个长的字符&#xff0c;而后去重后方式一个词表。 使用特殊1024 个tok…

解决方案:Mac 安装 pip

python3 --version 通过以下命令来下载pip&#xff1a; curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py curl命令允许您指定一个直接下载链接。使用-o选项来设置下载文件的名称。 通过运行以下命令安装下载的包&#xff1a; python3 get-pip.py

【开源】基于JAVA的医院门诊预约挂号系统

项目编号&#xff1a; S 033 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S033&#xff0c;文末获取源码。} 项目编号&#xff1a;S033&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 功能性需求2.1.1 数据中心模块2.1.2…

Day02 Liunx高级程序设计2-文件IO

系统调用 概念 是操作系统提供给用户使其可以操作内核提供服务的一组函数接口 用户态和内核态 其中 ring 0 权限最高&#xff0c;可以使用所有 CPU 指令&#xff0c; ring 3 权限最低&#xff0c;仅能使用 常规 CPU 指令&#xff0c;这个级别的权限不能使用访问硬件资…

深度学习在图像识别中的应用

深度学习在图像识别中的应用 摘要&#xff1a;本文介绍了深度学习在图像识别领域的应用&#xff0c;包括卷积神经网络&#xff08;CNN&#xff09;的基本原理、常见模型以及在图像识别中的优势。并通过实验展示了深度学习在图像识别中的实际应用和效果。 一、引言 随着数字化…

写给初学者的 HarmonyOS 教程 -- 状态管理(@State/@Prop/@Link 装饰器)

State 装饰的变量&#xff0c;或称为状态变量&#xff0c;一旦变量拥有了状态属性&#xff0c;就和自定义组件的渲染绑定起来。当状态改变时&#xff0c;UI 会发生对应的渲染改变&#xff08;类似 Compose 的 mutablestateof &#xff09;。 Prop 装饰的变量可以和父组件建立单…

深度学习在计算机视觉中的应用

深度学习在计算机视觉中的应用 摘要&#xff1a;本文介绍了深度学习在计算机视觉领域的应用&#xff0c;包括目标检测、图像分类、人脸识别等。通过分析深度学习在计算机视觉中的实际应用案例&#xff0c;阐述了深度学习在计算机视觉中的优势和未来发展趋势。 一、引言 计算…

使用rust slint开发桌面应用

安装QT5&#xff0c;过程省略 安装rust&#xff0c;过程省略 创建工程 cargo new slint_demo 在cargo.toml添加依赖 [dependencies] slint "1.1.1" [build-dependencies] slint-build "1.1.1" 创建build.rs fn main() {slint_build::compile(&quo…

8.HTTP工作原理

HTTP是什么 HTTP工作原理 HTTP协议的请求类型和响应状态码 总结 1.HTTP是什么 HTTP超文本传输协议就是在一个网络中上传下载文件的一套规则 2.HTTP工作原理 HTTP超文本传输协议的本质是TCP通信&#xff0c;链接—>请求—>响应—>断开 3.HTTP协议的请求类型和响应状…

Java+Swing+Mysql实现超市管理系统

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;IDEA2018 JDK版本&#xff1a;jdk1.8 数据库&#xff1a;Mysql8.0 2.技术选型 JavaSwingMysql 3.功能模块 4.系统功能 1.系统登录登出 管理员可以登录、退出系统 2.商品信息管理 管理员可以对商品信息…

Android画布Canvas绘制drawBitmap基于源Rect和目的Rect,Kotlin

Android画布Canvas绘制drawBitmap基于源Rect和目的Rect&#xff0c;Kotlin <?xml version"1.0" encoding"utf-8"?> <androidx.appcompat.widget.LinearLayoutCompat xmlns:android"http://schemas.android.com/apk/res/android"xmlns…

Cannot find module ‘node:url‘报错处理

在运行vite搭建的项目时&#xff0c;遇到Cannot find module node:url’报错。具体错误如图所示&#xff1a; 造成以上问题的原因是node版本较低。Vite 需要 Node.js 版本 14.18&#xff0c;16。 解决方案&#xff1a; 上面是通过nvm切换高版本node。 再次执行运行命令&…

基于Springboot的社区医院管理服务系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的社区医院管理服务系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

C语言--每日选择题--Day36

第一题 1. 以下关于指针的说法,正确的是() A&#xff1a;int *const p 与 int const *p等价 B&#xff1a;const int *p 与 int *const p等价 C&#xff1a;const int *p 与 int const *p 等价 D&#xff1a;int *p[10] 与 int (*p)[10] 等价 答案及解析 C const 在*的左侧&…

缓存穿透、击穿、雪崩

缓存穿透&#xff1a; 指的是恶意用户或攻击者通过请求不存在于缓存和后端存储中的数据来使得所有请求都落到后端存储上&#xff0c;导致系统瘫痪。 解决方案&#xff1a; 通常包括使用布隆过滤器或者黑白名单等方式来过滤掉无效请求&#xff0c;以及在应用程序中加入缓存预热…