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

news2024/11/27 22:25:21

为什么要使用线程池

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

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

在这里插入图片描述

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

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

在这里插入图片描述

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.coloradmin.cn/o/1286774.html

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

相关文章

设计一个简易版本的分布式任务调度系统

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理&#x1f525;如果感觉博主的文章还不错的话&#xff…

【Math】高斯分布的乘积 Product of Guassian Distribution【附带Python实现】

【Math】高斯分布的乘积 Product of Guassian Distribution【附带Python实现】 文章目录 【Math】高斯分布的乘积 Product of Guassian Distribution【附带Python实现】1.推导2. CodeReference 结果先放在前面 1.推导 在学习PEARL算法的时候&#xff0c;encoder的设计涉及到了…

读书笔记-《数据结构与算法》-摘要3[选择排序]

选择排序 核心&#xff1a;不断地选择剩余元素中的最小者。 找到数组中最小元素并将其和数组第一个元素交换位置。在剩下的元素中找到最小元素并将其与数组第二个元素交换&#xff0c;直至整个数组排序。 性质&#xff1a; 比较次数(N-1)(N-2)(N-3)…21~N^2/2交换次数N运行…

jquery 判断是手机端还是电脑端

判断为手机端&#xff1a; var sUserAgent navigator.userAgent.toLowerCase(); var bIsIpad sUserAgent.match(/ipad/i) "ipad"; var bIsIphoneOs sUserAgent.match(/iphone os/i) "iphone os"; var bIsMidp sUserAgent.match(/midp/i) "mid…

Navicat在分辨率不同的屏幕窗口显示大小不一致问题解决

1.主屏幕为2560*1600分辨率&#xff0c;能够显示较多数据连接 2.在第二屏幕分辨率低&#xff0c;字体变大&#xff0c;显示内容变少 解决办法&#xff1a; 1.右击navicat图标-属性 2.选择【兼容性】-在兼容性页面中选择**“更改高DPI设置”** 3…勾选“高DPI缩放替代”&a…

chown和chmod

chown和chmod都是在Linux和Unix系统中用于设置文件和文件夹权限的命令&#xff0c;但它们的功能和用途有所不同。 功能&#xff1a;chown主要用于修改文件或文件夹的所有者和所属组&#xff0c;而chmod则主要用于修改文件或文件夹的读写执行权限。用途&#xff1a;如果想要授权…

GD32F103*固件库移植FreeRTOS详细教程与解析

GD32F103*固件库移植FreeRTOS详细教程与解析 GD32F103*移植μCOS-Ⅲ详细教程与解析&#xff0c;欢迎指正 文章目录 GD32F103*固件库移植FreeRTOS详细教程与解析前言一、移植前的准备二、移植步骤1.文件结构2.添加代码3.编译与配置 三、注意事项总结 前言 FreeRTOS是一个可以基…

力扣973. 最接近原点的 K 个点(java 排序法,大顶堆法)

Problem: 973. 最接近原点的 K 个点 文章目录 题目描述思路解题方法复杂度Code 题目描述 给定一个数组 points &#xff0c;其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点&#xff0c;并且是一个整数 k &#xff0c;返回离原点 (0,0) 最近的 k 个点。 这里&#xff0c;平面…

.NET微信网页开发相关文章教程

前言 今天我们主要总结一下.NET微信网页开发的相关文章教程。 微信网页开发详细文档可以看微信官方文档&#xff1a;背景 | 微信开放文档 全面的.NET微信网页开发之JS-SDK使用步骤、配置信息和接口请求签名生成详解 微信官方文档对于accessToken和jsapi_ticket生成的示例代码…

智能优化算法应用:基于类电磁机制算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于类电磁机制算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于类电磁机制算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.类电磁机制算法4.实验参数设定5.算法结果…

最全Web前端校招面试真题合集(附答案)

历时半年&#xff0c;我们整理了这份市面上最全面的前端校招面试题解析大全。 包含了腾讯、字节跳动、百度、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目。希望对大家参加前端校招有所帮助吧&#xff01; HTML 浏览器页面有哪三层构成&…

sql面试题之累计消耗问题

sql中累计求和是我们比较经常遇到的问题&#xff0c;那么与之相反的累计消耗的问题不知你是否挑战过 –问题&#xff1a;在活动大促中&#xff0c;有玩游戏瓜分奖金环节。现有奖金池为3000元&#xff0c;代表奖金池中的初始额度 表中的数据代表每一个用户和其对应的得分&#…

vscode git管理

vscode添加了git管理 1、如下按钮&#xff0c;可以看到本次的修改部分 2、安装git history 就可以查看每次的不同部分了

Javafx实现浏览器

浏览器是一种计算机程序&#xff0c;主要用于显示互联网上的网页。通过浏览器&#xff0c;用户可以访问各种网站、搜索引擎、在线应用程序、社交媒体等。常见的浏览器包括Google Chrome、Mozilla Firefox、Safari、Microsoft Edge、Opera等。浏览器的功能不仅限于浏览网页&…

如何将微服务注册到eureka-server中

将需要注册到eureka-server的服务的maven的pom文件中添加eureka-client依赖 <!--eureka-client依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>&l…

白盒测试法如何进行单元测试

摘要&#xff1a; 单元测试是软件测试的基础&#xff0c;本文详细的论述了单元测试的两个步骤人工静态检查法与动态执行法&#xff0c;所需执行的工作项目及相关的策略和方法。通过对这两个步骤的描述作者将多年的单元测试经验及测试理论注入于全文。 白盒测试法如何进行单元…

在外包待了6年,技术退步太明显......

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

升降压型LED恒流驱动芯片,升降压LED恒流驱动IC

升降压型LED恒流驱动芯片AH1120 是一种高性能的LED驱动解决方案&#xff0c;它能够提供稳定、精确的电流输出&#xff0c;以满足各种LED照明应用的需求。这种芯片具有多种优点&#xff0c;包括高恒流精度、优异的母线和负载调整率、宽输入电压范围、高效率、工作频率可调、智能…

Web 应用程序性能测试核心步骤

通常大家做web 应用程序的时候会有哪些操作呢&#xff1f;今天就来看看常见的web 应用程序的常见操作。 Web 应用程序性能测试核心步骤 1&#xff1a;识别测试环境。确定物理测试环境和生产环境&#xff0c;以及测试团队可用的工具和资源。物理环境包括硬件、软件和网络配置。…

RT-Thread Studio文件消失不见或被排除构建

不得不说RT-Thread Studio里面配置真多&#xff0c;今天我同事的电脑发现根本没有被画斜杠的文件夹&#xff0c;导致我想移植f1的写内部flash这个&#xff08;可以看上一个文章&#xff09;时候不能直接点击属性排除构建&#xff0c;然后在网上查找的时候也没怎么找到说法&…