【多线程】 —— 线程池

news/2025/2/23 16:07:07

文章目录

  • 1、什么是线程池,线程池有哪些(创建)
    • (1) newCachedThreadPool
    • (2) newFixedThreadPool
    • (3) newSingleThreadExecutor
    • (4) newScheduleThreadPool
  • 2、为什么要使用线程池?
  • 3、线程池底层工作原理
  • 4、ThreadPoolExecutor 对象有哪些参数? 怎么设定核心线程数和最大线程数? 拒绝策略有哪些?
      • 1) corePoolSize:核心线程数,
      • (2) maximumPoolSize:最大线程数
      • (3) keepAliveTime:存活时间,
      • (4) unit:keepAliveTime 的单位。
      • (5) workQueue:任务队列
      • (6) threadFactory:线程工厂,
      • (7) RejectedExecutionHandler:拒绝策略
    • 线程池大小设置
    • 拒绝策略
  • 5、常见的线程安全的并发容器有哪些?

1、什么是线程池,线程池有哪些(创建)

线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用 new 线程而是
直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。

在JDK的java.uti.concurrent./executors类中提供了生成多种不同线程池的静态方法

java">ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(4);
ScheduledExecutorService newScheduledThreadPool =
Executors.newScheduledThreadPool(4);
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();

然后调用他们的 execute 方法即可。
这 4 种线程池底层 全部是 ThreadPoolExecutor 对象的实现,阿里规范手册中规定线
程池采用 ThreadPoolExecutor 自定义的,实际开发也是。

(1) newCachedThreadPool

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若
无可回收,则新建线程。这种类型的线程池特点是:
工作线程的创建数量几乎没有限制(其实也有限制的,数目为 Interger.
MAX_VALUE), 这样可灵活的往线程池中添加线程。
如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为
1 分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程
池重新创建一个工作线程。
在使用 CachedThreadPool 时,一定要注意控制任务的数量,否则,由于大量线程
同时运行,很有会造成系统瘫痪。

(2) newFixedThreadPool

创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如
果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
FixedThreadPool 是一个典型且优秀的线程池,它具有线程池提高程序效率和节省
创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任
务时,它不会释放工作线程,还会占用一定的系统资源。

(3) newSingleThreadExecutor

创建一个单线程化的 Executor,即只创建唯一的工作者线程来执行任务,它只会
用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)
执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最
大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是
活动的。

(4) newScheduleThreadPool

创建一个定长的线程池,而且支持定时的以及周期性的任务执行。例如延迟 3 秒
执行。

2、为什么要使用线程池?

(1) 线程池做的工作主要是控制运行的线程数量,处理过程中将任务放入队列,然
后在线程创建后启动这些任务,如果线程数量超过了最 大数量,超出数量的线程排队
等候,等其它线程执行完毕,再从队列中取出任务来执行。

(2) 主要特点:线程复用;控制最大并发数:管理线程。
第一: 降低资源消耗。通过重复利用己创建的线程降低线程创建和销毁造成的消
耗。
第二: 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执
行。
第三: 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系
统资源,还会降低系统的稳定性,使用线程池可以进 行统一的分配,调优和监控

3、线程池底层工作原理

在这里插入图片描述

  • (1) 第一步:线程池刚创建的时候,里面没有任何线程,等到有任务过来的时候才会
    创建线程。当然也可以调用 prestartAllCoreThreads() 或
    者 prestartCoreThread() 方法预创建 corePoolSize 个线程
  • (2) 第二步:调用 execute()提交一个任务时,如果当前的工作线程数
    <corePoolSize,直接创建新的线程执行这个任务
  • (3) 第三步:如果当时工作线程数量>=corePoolSize,会将任务放入任务队列中缓存
  • (4) 第四步:如果队列已满,并且线程池中工作线程的数量<maximumPoolSize,还是
    会创建线程执行这个任务
  • (5) 第五步:如果队列已满,并且线程池中的线程已达到 maximumPoolSize,这个时
    候会执行拒绝策略,JAVA 线程池默认的策略是 AbortPolicy,即抛出
    RejectedExecutionException 异常

4、ThreadPoolExecutor 对象有哪些参数? 怎么设定核心线程数和最大线程数? 拒绝策略有哪些?

首先我们都知道有7个参数:

1) corePoolSize:核心线程数,

在 ThreadPoolExecutor 中有一个与它相关的配置:allowCoreThreadTimeOut(默
认为 false),当 allowCoreThreadTimeOut 为 false 时,核心线程会一直存活,
哪怕是一直空闲着。而当 allowCoreThreadTimeOut 为 true 时核心线程空闲时间
超过 keepAliveTime 时会被回收。

(2) maximumPoolSize:最大线程数

线程池能容纳的最大线程数,当线程池中的线程达到最大时,此时添加任务将会采
用拒绝策略,默认的拒绝策略是抛出一个运行时错误
(RejectedExecutionException)。值得一提的是,当初始化时用的工作队列为
LinkedBlockingDeque 时,这个值将无效。

(3) keepAliveTime:存活时间,

当非核心空闲超过这个时间将被回收,同时空闲核心线程是否回收受
allowCoreThreadTimeOut 影响。

(4) unit:keepAliveTime 的单位。

(5) workQueue:任务队列

常用有三种队列,即 SynchronousQueue,LinkedBlockingDeque(无界队
列),ArrayBlockingQueue(有界队列)。

(6) threadFactory:线程工厂,

ThreadFactory 是一个接口,用来创建 worker。通过线程工厂可以对线程的一些属
性进行定制。默认直接新建线程。

(7) RejectedExecutionHandler:拒绝策略

也是一个接口,只有一个方法,当线程池中的资源已经全部使用,添加新线程被拒
绝时,会调用 RejectedExecutionHandler 的 rejectedExecution 法。默认是抛出一
个运行时异常。

线程池大小设置

线程池大小设置:

  1. 需要分析线程池执行的任务的特性: CPU 密集型还是 IO 密集型
  2. 每个任务执行的平均时长大概是多少,这个任务的执行时长可能还跟任务处理
    逻辑是否涉及到网络传输以及底层系统资源依赖有关系

如果是 CPU 密集型,主要是执行计算任务,响应时间很快,cpu 一直在运行,这
种任务 cpu 的利用率很高,那么线程数的配置应该根据 CPU 核心数来决定,CPU
核心数=最大同时执行线程数,加入 CPU 核心数为 4,那么服务器最多能同时执行
4 个线程。过多的线程会导致上下文切换反而使得效率降低。那线程池的最大线程
数可以配置为 cpu 核心数+1 ;

如果是 IO 密集型,主要是进行 IO 操作,执行 IO 操
作的时间较长,这是 cpu 出于空闲状态,导致 cpu 的利用率不高,这种情况下可
以增加线程池的大小。这种情况下可以结合线程的等待时长来做判断,等待时间越
高,那么线程数也相对越多。一般可以配置 cpu 核心数的 2 倍。

一个公式:线程池设定最佳线程数目 = ((线程池设定的线程等待时间+线程
CPU 时间)/
线程 CPU 时间 )* CPU 数目
这个公式的线程 cpu 时间是预估的程序单个线程在 cpu 上运行的时间(通常使用
loadrunner 测试大量运行次数求出平均值)

拒绝策略

  1. AbortPolicy:直接抛出异常,默认策略;
  2. CallerRunsPolicy:用调用者所在的线程来执行任务;
  3. DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
  4. DiscardPolicy:直接丢弃任务;当然也可以根据应用场景实现
    RejectedExecutionHandler 接口,自定义饱和策略,如记录日志或持久化存储不能处
    理的任务

5、常见的线程安全的并发容器有哪些?

CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMap
CopyOnWriteArrayList、CopyOnWriteArraySet 采用写时复制实现线程安全
ConcurrentHashMap 采用分段锁的方式实现线程安全


还可参考以下文章:
1、Java线程池7个参数详解

2、线程池


http://www.niftyadmin.cn/n/4952848.html

相关文章

【LeetCode 算法】Add Two Integers 两整数相加-位运算

文章目录 Add Two Integers 两整数相加问题描述&#xff1a;分析代码递归 Tag Add Two Integers 两整数相加 问题描述&#xff1a; 给你两个整数 num1 和 num2&#xff0c;返回这两个整数的和。 − 100 < n u m 1 , n u m 2 < 100 -100 < num1, num2 < 100 −1…

idea 本地版本控制 local history

idea 本地版本控制 local history 如何打开 1 自定义快捷键 settings->keymap->搜索框输入 show history -》Add Keyboard Shortcut -》设置为 CtrlAltL 2 右键文件-》local history -》show history 新建文件 版本1&#xff0c;creating class com.geekmice…这个是初…

分布式消息中间件

消息中间件是Java开发消息队列的一种中间件产品。中间件类似windows编程开发中的插件。工具插件在软件工具中是中间插件。插件也是应用程序。消息的分发过程包装之后是chatlog 系统或者是手机短信。系统与系统之间的通信通过消息的发送和接收。堆积频繁过多的系统通知消息需要进…

【计算机视觉|生成对抗】StackGAN:使用堆叠生成对抗网络进行文本到照片逼真图像合成

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;StackGAN: Text to Photo-realistic Image Synthesis with Stacked Generative Adversarial Networks 链接&#xff1a;[1612.03242] StackGAN: Text to Photo-realistic Image Synthesis…

【面试复盘】知乎暑期实习算法工程师二面

来源&#xff1a;投稿 作者&#xff1a;LSC 编辑&#xff1a;学姐 1. 自我介绍 2. 介绍自己的项目 3. 编程题 判断一个链表是不是会文链表class ListNode: def __init__(self, val, nextNone):self.val valself.next nextdef reverse(head):pre Nonep headwhile p ! No…

服务器安装centos7踩坑

1、制作启动工具 下载iso https://developer.aliyun.com/mirror/?spma2c6h.25603864.0.0.20387abbo2RFbn http://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/?spma2c6h.25603864.0.0.1995f5ad4AhJaW下载 UltraISO https://cn.ultraiso.net/插入u盘启动 到了如图所示页面…

windows批处理set命令:设置变量,计算表达式

文章目录 基础模式表达式模式变量输入模式环境变量 基础模式 变量是一切编程的基础&#xff0c;在批处理语言中&#xff0c;通过set设置变量&#xff0c;而在调用变量时&#xff0c;需要在变量两端加上百分号&#xff0c;例如 set a1 echo %a%运行结果为 >set a1 >ech…

JavaFx 实现水平滚动文本(跑马灯效果)

本文是以TornadoFx框架进行编写,各位使用JavaFx可以参考 代码已经封装在common-controls库中 效果 代码 实现原理就是利用了JavaFx里的动画效果去修改scrollpane的translateX属性,原本想在text上改造的,发现文字过多就不行了,最终还是使用了scrollpane组件来完成功能 就是需…