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();
                    }
                }
            });
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能优化算法应用:基于寄生捕食算法无线传感器网络(WSN)覆盖优化 - 附代码

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

深入探讨Guava的缓存机制

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;今天咱们聊聊Google Guava的缓存机制。缓存在现代编程中的作用非常大&#xff0c;它能提高应用性能&#xff0c;减少数据库压力&#xff0c;简直就是性能优化的利器。而Guava提供的缓存功能&#xff0c;不仅强大…

vue el-select多选封装及使用

使用了Element UI库中的el-select和el-option组件来构建多选下拉框。同时&#xff0c;也包含了一个el-input组件用于过滤搜索选择项&#xff0c;以及el-checkbox-group和el-checkbox组件用于显示多选项。 创建组件index.vue (src/common-ui/selectMultiple/index.vue) <tem…

【优选算法系列】【专题一双指针】第四节.15. 三数之和和18. 四数之和

文章目录 前言一、三数之和 1.1 题目描述 1.2 题目解析 1.2.1 算法原理 1.2.2 代码编写 1.2.3 题目总结二、四数之和 2.1 题目描述 2.2 题目解析 2.2.1 算法原理 2.2.2 代码编写 …

什么是动态住宅IP?它有什么用途?

随着网络的迅速发展&#xff0c;许多人对代理IP已经有了比较深刻的认识&#xff0c;并且广泛地运用到了各自的业务中&#xff0c;尤其在跨境的相关业务中表现尤其卓越。对于代理IP的类别&#xff0c;也需要根据自己的业务类型具体选择最合适的&#xff0c;那么今天IPFoxy就给大…

【Vue】使用cmd命令创建vue项目

上一篇&#xff1a; node的安装与配置 https://blog.csdn.net/m0_67930426/article/details/134562278?spm1001.2014.3001.5502 目录 一.创建空文件夹专门存放vue项目 二. 查看node , npm 和vue脚手架的版本 三.安装vue脚手架 四.创建vue项目 五.运行项目 一.创建空文件…

File类—递归文件搜索执行脚本文件

文章目录 一、需求分析二、File类2.1 File对象的创建2.2 File判断和获取方法2.3 创建和删除方法2.4 遍历文件夹方法 三、Runtime类—常见api四、递归文件搜索执行脚本文件 一、需求分析 在本篇博客中&#xff0c;我们想通过递归文件的方式&#xff0c;在D:\\判断下搜索QQ.exe这…

Hadoop学习笔记(HDP)-Part.07 安装MySQL

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

生成式 AI 应用落地小结:高估的模型能力,低估的工程实施

虽然 ChatGPT 已经诞生了一周年&#xff0c;但是大量的人依旧对于生成式 AI 没有足够的认识。在研发领域&#xff0c;Thoughtworks 一直在与不同的大型企业合作&#xff0c;保持开放性的探索。 在我负责的 Thoughtworks 开源社区&#xff0c;我们与外部的几家大型企业一起探索和…

YOLOv8创新魔改教程(三)如何添加注意力机制注意力机制的用法与思考

注意力机制的用法与思考 好多同学问我加了CA注意力机制&#xff0c;CBAM注意力机制&#xff0c;都没有涨点&#xff0c;然后就在不停地换不同的注意力机制&#xff0c;其实并不是这样的。今天和大家讨论一下注意力机制的用法与思考。 &#xff08;一&#xff09;添加位置 大…

Vmware17虚拟机安装windows10系统

不要去什么系统之家之类的下载镜像&#xff0c;会不好安装&#xff0c;镜像被魔改过了&#xff0c;适合真实物理机上的系统在PE里安装系统&#xff0c;建议下载原版系统ISO文件 安装vmware17pro 下载地址https://dwangshuo.jb51.net/202211/tools/VMwareplayer17_855676.rar 解…

vue3中手写一个日历,年部分,月部分,周部分,日部分

效果图 高度自定义&#xff0c;支持每天的统计展示&#xff0c;弹窗展示&#xff0c;详情操作 月部分&#xff1a; 默认展示当前月&#xff0c;支持前进和后退选择下一月 支持自定义每月的展示数据&#xff0c; 周部分&#xff1a; 分为上下午&#xff0c;可以列出要做的事项…

BitWarden数据迁移以及邮箱SMTP配置

bitwarden 个人密码库&#xff0c;这是我玩nas之后最想推荐的一个东西&#xff0c;今天就来分享一下 之前使用bitwarden都是网上现成的文章照抄&#xff08;能搜到的都是抄来抄去的简直离谱&#xff09;&#xff0c;导致邮箱无法使用、数据库也只是本地的sqlLite很不方便。 前…

人工智能对我们的生活影响有多大?

一、标题解析 本文标题为“人工智能对我们的生活影响有多大&#xff1f;”&#xff0c;这是一个典型的知乎风格SEO文案标题&#xff0c;既能够吸引读者&#xff0c;又能够体现文章的核心内容。 二、内容创作 1. 引言&#xff1a;在开头&#xff0c;我们可以简要介绍人工智能…

MySQL的时间与日期函数

1、日期格式 DATE_FORMAT("20231128", %Y-%m-%d) -- 2023-11-28 DATE_FORMAT("2023-11-28", %Y-%m-%d) -- 2023-11-28 DATE_FORMAT(2023-11-28 08:47:23, %H:%i:%s) -- 08:47:23 (24小时制) DATE_FORMAT(2023-11-28 08:47:23, %h:%i:%s) -- 08:47:23(12小…

九九乘法表-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第13讲。 九九乘法表&#…

【机器学习】聚类(三):原型聚类:高斯混合聚类

文章目录 一、实验介绍1. 算法流程2. 算法解释3. 算法特点4. 应用场景5. 注意事项 二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 导入必要的库1. 全局调试变量2. 调试函数3. 高斯密度函数&#xff08;phi&#xff09;4. E步&#xff08;getExpectation&#xff09…

class文件结构

文章目录 1. 常量池集合2. 访问标志3. 字段表集合4. 方法表集合5. 属性表集合 成员变量&#xff08;非静态&#xff09;的赋值过程&#xff1a;1. 默认初始化 2. 显示初始化/代码块中初始化 3. 构造器中初始化 4. 有了对象后对象。属性或者对象。方法的方式对成员变量进行赋值 …

JVM之四种引用类型(五)

JVM 系列吊打面试官&#xff1a;说一下 Java 的四种引用类型 四种引种类型 1.强引用 在 Java 中最常见的就是强引用&#xff0c;把一个对象赋给一个引用变量&#xff0c;这个引用变量就是一个强引用。当一个对象被强引用变量引用时&#xff0c;它处于可达状态&#xff0c;它是…

RPG项目01_UI面板Game

基于“RPG项目01_技能释放”&#xff0c;将UI包导入Unity场景中&#xff0c; 将图片放置 拖拽 取消勾选&#xff08;隐藏攻击切片&#xff09; 对技能添加蒙版 调节父子物体大小一致 将子类蒙版复制 执行5次 运行即可看到技能使用完的冷却条 在Scripts下创建UI文件夹 写代码&am…