【JUC】九、线程池ThreadPool

news2024/11/26 16:40:16

文章目录

  • 1、线程池
  • 2、分类
  • 3、线程池的使用
  • 4、工作流程
  • 5、拒绝策略
  • 6、线程池的七个参数
  • 7、自定义线程池
  • 8、什么时候考虑使用线程池?

1、线程池

线程池和数据库连接池的理念很相似,对于数据库连接池:普通的连接数据库是建立一个JDBC连接,执行完sql之后,就会关闭,即销毁connection对象,再次连接还需要重复上述步骤。当与数据库交互频繁时,这种模式会严重影响程序的性能,因此有了数据库连接池。对应到线程池thread pool,就是线程池里维护着多个线程,等待监督管理者分配执行任务。线程池带来的好处就是:

  • 降低资源消耗:降低避免频繁创建和销毁线程的代价
  • 提高响应速度:任务达到时,不用再等待创建线程
  • 线程管理方便:线程过多,调度开销大,用线程池可防止过分调度,且可以做统一的监控、分配、调优

关于线程切换的例子:10 年前单核 CPU 电脑,假的多线程,像马戏团小丑玩多个球,CPU 需要来回切换。 现在是多核电脑,多个线程各自跑在独立的 CPU 上,不用频繁切换,效率高。

2、分类

Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executors(工具类)、ExecutorsExecutorService、ThreadPoolExecutor这几个类
在这里插入图片描述

线程池有以下几类:

  • 一池N线程:Executors.newFixedThreadPool(int num)
  • 一池一线程:Executors.newSingleThreadExecutor()
  • 可扩容池,根据需求创建一定数量的线程,遇强则强:Executors.newCachedThreadPool()

3、线程池的使用

  • 创建线程池对象
  • 调用execute方法提交任务
public class ThreadPoolDemo {

    public static void main(String[] args) {
        //一池五线程
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        //一池1线程
        ExecutorService threadPool1 = Executors.newSingleThreadExecutor();
        //一池可扩容线程
        ExecutorService threadPool2 = Executors.newCachedThreadPool();
        //提交10次任务到线程池
        try{
            for (int i = 1; i <= 20; i++) {
                //提交任务到另一线程(线程池中的)
                threadPool2.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "线程正在办理业务");
                });
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            threadPool2.shutdown();
        }

    }
}

以可扩容线程池为例:

在这里插入图片描述

4、工作流程

在这里插入图片描述

如图,此时常驻线程数为2,最大线程数为5,阻塞队列长度为3(黑点),此时来了两个任务1和2 ⇒ 直接常驻线程 ⇒ 那两个任务还执行完,又来了几个任务3、4、5 ⇒ 这时不是直接上最大线程,而是进入阻塞队列 ⇒ 此时又来了三个人6、7、8 ⇒ 发现阻塞队列也满了,那就开启最大线程处理6、7、8的业务 (注意新开的线程不是去处理阻塞队列了,阻塞队列的3、4、5还是在队列中继续等待) ⇒ 此时又来了一个任务9 ⇒ 走拒绝策略

注意这几点:

ExecutorService pool = Executors.newSingleThreadExecutor();
  • 执行上面这句,并不会创建线程,而是执行pool.execute方法提交任务时才创建
  • 常驻线程用完了,再来任务,不是直接按最大线程数启动新线程,而是阻塞队列
  • 阻塞队列满了以后,按最大线程数启动新线程,且新线程处理的不是阻塞队列里的任务

看下源码,从提交任务的execute方法打断点,进入execute方法:

在这里插入图片描述

在这里插入图片描述

5、拒绝策略

阻塞队列和最大线程数量都用完后,走拒绝策略,JDK内置的拒绝策略有:

  • AbortPoligy(默认):直接抛出RejectedExecutionExption异常阻止系统正常运行
  • CallerRunsPoliy:既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,谁让你来的,你找谁去
  • DiscardOldestPoliy:抛弃阻塞队列中等待最久的任务,然后把当前任务加入队列中
  • DiscardPolicy:默默地丢弃无法处理的任务,不予任何处理也不抛出异常,如果允许任务丢失,这是最好的一种策略

6、线程池的七个参数

查看源码可以发现,不管是三种线程池中的哪种,最后都是return new ThreadPoolExecutor,关于ThreadPoolExecutor类:

在这里插入图片描述

  • int corePoolSize:常驻线程数量
  • int maximumPoolSize:最大线程数量
  • long keepAliveTime:线程存活时间,线程多长时间没被使用就关闭
  • TimeUnit unit:存活时间的单位
  • BlockingQueue workQueue:常驻线程用完了,再来请求线程,进入阻塞队列
  • ThreadFactory threadFactory:线程工厂
  • RejectedExecutionHandler handler:拒绝策略

以银行为例对比:银行大厅一共有10个窗口(最大线程数量),但平时一般只开5个(常驻线程数量),某天办理业务的人很多,5个窗口不够用,其余人来了就先在大厅椅子上坐着等(阻塞队列),结果椅子坐满了,还有人陆续来,于是10个窗口全开,还来很多人,那就只能告诉新来的今天轮不到你办了(拒绝策略)。

7、自定义线程池

Executors工具类可以创建三种线程池,但通常自定义线程池是因为,Executors返回的线程池对象有以下两个问题:

  • 对于FixedThreadPool和SingleThreadPool,代码底层用的阻塞队列是LinkedBlockingQueue类型的,队列长度为Integer.MAX_VALUE,可能堆积大量请求,导致OOM
  • 对于CachedThreadPool,其源码中写的最大线程数量为Integer.MAX_VALUE,创建大量线程,调度难度大且会OOM
public class ThreadPoolDemo2 {

    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,    //常驻或核心线程数
                5,    //最大线程数
                2L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),  //阻塞队列
                Executors.defaultThreadFactory(), 
                new ThreadPoolExecutor.AbortPolicy()  //拒绝策略
        );
        try {
            for (int i = 1; i <= 20; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "线程正在办理业务");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

在这里插入图片描述

8、什么时候考虑使用线程池?

到这儿,线程池的作用、分类、底层代码逻辑、参数与策略的问题基本清晰,那什么时候考虑去使用线程池呢?==> 线程池适合处理耗时任务,可以充分使用目前服务器的硬件资源,加快处理速度。更确切的说是:

  • 单个任务处理时间比较短
  • 但需要处理的任务的数量大

此时,如果不使用线程池,随意启动许多线程,容易导致系统因创建大量线程而OOM且过渡调度(过渡切换)。比如工作中遇到一个excel数据转换后批量写入库里,就可拆为一批批的小任务去insert。还有帖子说需要限制并发执行的任务数量时也可以用线程池,这儿我先想到的反而是Semaphore信号灯这个JUC辅助类。

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

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

相关文章

本地开发环境和服务器传输数据的几种方法

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

注册表单mvc

jsp给我们的ControllerServlet 1在哪看到我们的数据呢 2什么时候用了session,有什么用 register.jsp 获取表单的name,email formBean.name是怎么定义的 3为什么就可以formbean访问 要使用的jsp对象都在servlet里面用setAttribute定义的 request.getSession().setAttribute…

听GPT 讲Rust源代码--library/core/src(8)

题图来自 Hello, crustaceans. File: rust/library/core/src/future/ready.rs 在Rust源代码中&#xff0c;rust/library/core/src/future/ready.rs文件的作用是定义了一个名为Ready的Future类型。Ready是一个简单的Future实现&#xff0c;它立即返回一个给定的值。 Ready 是一个…

大数据Doris(二十四):数据导入(Stream Load)介绍

文章目录 数据导入(Stream Load)介绍 一、适用场景 二、基本原理

quartz笔记

Quartz-CSDN博客 上面是Quartz的一些基本知识,如果对quartz的基本API不是很了解的话,建议先看下上面的 和Linux Crontab对比 1.执行粒度: Linux Crontab是进程级 quart是线程级 2.跨平台性: Crontab只能在Linxu运行 quart是java实现,可以跨平台 3.调度集上 Crontab的…

网络的概念与定义

一.网络的概念与定义 1.1 网络的概念 具有独立功能的计算机通过通信介质连接起来就形成了网络。为了满足人们的各种需求&#xff0c;比如访问网页&#xff0c;在线游戏&#xff0c;在线视频等&#xff0c;会形成比如文本&#xff0c;图片&#xff0c;视频等都是信息的不同呈现方…

【AI视野·今日NLP 自然语言处理论文速览 第六十四期】Fri, 27 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Fri, 27 Oct 2023 Totally 80 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers torchdistill Meets Hugging Face Libraries for Reproducible, Coding-Free Deep Learning Studies: A Case …

11.16 知识总结(模型层更多内容)

一、 多表查询&#xff08;跨表查询&#xff09; <br class"Apple-interchange-newline"><div></div> 子查询&#xff1a;分步查询 链表查询&#xff1a;把多个有关系的表拼接成一个大表(虚拟表) inner join left join right join 1.1 基于双下划…

【EI会议征稿】第三届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2024)

第三届网络安全、人工智能与数字经济国际学术会议&#xff08;CSAIDE 2024&#xff09; 2024 3rd International Conference on Cyber Security, Artificial Intelligence and Digital Economy 第三届网络安全、人工智能与数字经济国际学术会议&#xff08;CSAIDE 2024&#…

鸿蒙4.0真机调试踩坑

传言鸿蒙next版本将不再兼容Android&#xff0c;所以领导安排做下鸿蒙开发的调研工作。 鸿蒙开发指南其实已经非常的友好了。但是鸿蒙开发本身还是有些坑要踩&#xff0c;这篇文章主要讲了鸿蒙真机调试问题。 目前手上的真机为华为 nova6&#xff0c;处理器为麒麟990.鸿蒙系统…

Python从 0 到 1 系统学习的全面详细内容

这里为大家梳理了一些Python从 0 到 1 系统学习的全面详细内容&#xff0c;想要系统的自学Python&#xff0c;希望我们可以提供一个框架&#xff0c;方便作为参考&#xff0c;学习Python。 1、为什么要学习Python&#xff1f; Python是一种功能强大的编程语言&#xff0c;它具…

WebGoat环境搭建

首先安装jdk&#xff0c;此步骤省略…验证 直接打开cmd&#xff0c;输入以下命令&#xff1a; java -version &#xff08;可以查看安装的JDK版本。&#xff09; javac &#xff08;查看java文件编译成的class文件&#xff09; WebGoat下载 WebGoat的下载地址&#xff1a;Relea…

x3daudio1_7.dll错误:解决方法和丢失原因及作用

x3daudio1_7.dll是Windows操作系统中的一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;主要作用是为DirectX音频提供支持。DirectX是微软推出的一套多媒体应用程序开发接口&#xff0c;广泛应用于游戏、多媒体制作等领域。x3daudio1_7.dll文件包含了许多与三维音频…

atoi函数的模拟实现

函数原型&#xff1a;int atoi (const char * str); 作用&#xff1a;将字符串转换为整数 注意事项&#xff1a; 1、会忽略字符串前的空白字符&#xff0c;并从第一个非空白字符开始解析整数&#xff0c;直到遇到非数字字符为止 具体代码如下&#xff1a; #include <s…

异行星平台--CRM系统搭建

使用异行行低代码平台搭建的CRM系统。CRM系统中&#xff0c;包括“客户”、“商机”、“合同”、“回款”、“开票”、“营销”、“回访”、“产品”、“联络人”、“销售订单”、“线索”。 “管理后台”可能是指一个用于管理后台系统的应用&#xff0c;可能包括对各种功能和数…

Logback 日志格式参数说明

打印日志格式&#xff1a; <property name"LOG_PATTERN" value"[${APP_NAME} ${SERVER_IP}:${SERVER_PORT}] %d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%X{traceId}-%X{spanId}] [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/&g…

HMM与LTP词性标注之LTP介绍

文章目录 LTP 上图缺点&#xff1a;参数太多&#xff0c;中文语料库匮乏 注意力机制&#xff0c;相当于给每一个词赋予一个权重&#xff0c;权重越大的越重要。 bert的缺点&#xff1a;神经元太多&#xff0c;较慢。 LTP 如果只是需要做词性的识别&#xff0c;那么用LTP就可…

与7无关的数

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…

Transformer原理详解

前言&#xff1a;好久没有用了&#xff0c;我已经快忘记了自己还有一个CSDN账号了。 在某位不知名好友的提醒下&#xff0c;终于拾起来了&#xff0c;自己也从大二转变成了研二。 目前研究方向主要为&#xff1a;时间序列预测&#xff0c;自然语言处理&#xff0c;智慧医疗 欢迎…

Win通过WSL配置安装Redis

一共分为如下几步&#xff1a; 安装WSL发行版&#xff0c;如Ubuntu安装Redis配置Redis与WSL WSL安装 这里有微软官方的文档&#xff1a;https://learn.microsoft.com/zh-cn/windows/wsl/install 但我不建议零基础的这么做。很容易输完一些命令之后&#xff0c;把环境弄得乱七…