线程池核心九问

2023-11-03 03:10
文章标签 线程 核心 九问

本文主要是介绍线程池核心九问,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.什么是线程池?

线程池就是提前创建若干个线程,
如果有任务需要处理,线程池里的线程就会处理任务,处理完之后线程并不会被销毁,而是等待下一个任务。减少频繁创建和销毁线程消耗系统资源。

2.为什么要用线程池 ?

频繁创建、销毁 线程,将是对系统资源的极大浪费。
因此,实际开发中我们将使用线程池来管理、复用线程。
使用线程池,可以
1.降低资源消耗: 重复利用线程,减少创建和销毁造成的消耗。
2.提升响应速度: 任务到达,不需要创建,立即执行。
3.提高可管理型: 线程是CPU调度和分派的基本单位,
如果无限制地创建,不仅会消耗系统资源,还会降低系统稳定性。
使用线程池可以统一进行 分配、调优和监控。

3.创建线程池的方式?

Java从1.5 Executors 类提供四种创建线程池方式
1).newSingleThreadExecutor()

  • 单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务,(队列长度-Integer.MAX_VALUE)

2).newFixedThreadPool(maximumPoolSize)

  • **定最大线程数,线程池 **,核心线程数=最大线程数=设置的线程数,可控制线程最大并发数,(队列长度-Integer.MAX_VALUE);

3).newCachedThreadPool()

  • 可缓存线程池,有任务才新建线程,闲置线程保存60秒 ,(最大线程数长度-Integer.MAX_VALUE)

4).newScheduledThreadPool(corePoolSize)

  • 定核心线程数,线程池,支持定时及周期性任务执行。(最大线程数长度-Integer.MAX_VALUE)
    在这里插入图片描述

在这里插入图片描述

4.为什么不建议使用 Executors静态工厂构建线程池

主要原因:队列堆积,有OOM风险
1.FixedThreadPool 和 SingleThreadPool
允许的请求队列(底层实现是LinkedBlockingQueue)长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM

2.CachedThreadPool 和 ScheduledThreadPool
允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

5.线程池参数

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) { }

corePoolSize:核心线程数量,一直存在,除非 allowCoreThreadTimeOut设置为true
maximumPoolSize:线程池允许的最大线程池数量 10
keepAliveTime:线程数量超过corePoolSize,空闲线程的最大超时时间
unit:超时时间的单位
workQueue:工作队列,保存未执行的Runnable 任务 (BlockingQueue 的实现类)
threadFactory:创建线程的工厂类
handler:当线程已满,工作队列也满了的时候,会被调用。被用来实现各种拒绝策略。

工作队列介绍
在这里插入图片描述

6.线程池的执行顺序

在这里插入图片描述

当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运
行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它
最终会收缩到 corePoolSize 的大小。

7.四种策略**

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
  • ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:**丢弃队列最老的任务,然后重新提交被拒绝的任务 **
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

8.实现原理

线程池由两个核心数据结构组成:
1)线程集合(workers):存放执行任务的线程,是一个HashSet;
2)任务等待队列(workQueue):存放等待线程池调度执行的任务,是一个阻塞式队列BlockingQueue;

8.如何合理设置线程池大小

任务一般可分为:CPU密集型、IO密集型、混合型,对于不同类型的任务需要分配不同大小的线程池。

  • CPU密集型任务: 尽量使用较小的线程池,一般为CPU核心数+1 ; (+1是利用等待空闲)
    • 因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。
  • IO密集型任务: 一般为2*CPU核心数。
    • IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。
  • 混合型任务
    • 可以将任务分成IO密集型和CPU密集型任务,然后分别用不同的线程池去处理。

线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

//java 中获取核心数 int availableProcessors = Runtime.getRuntime().availableProcessors();

9.线程池的动态规划参数动态化

JDK原生线程池ThreadPoolExecutor提供了如下几个public的setter方法,如下图所示:
在这里插入图片描述

JDK允许线程池使用方通过ThreadPoolExecutor的实例来动态设置线程池的核心策略,
以setCorePoolSize为方法例,
在运行期线程池使用方调用此方法设置corePoolSize之后,
线程池会直接覆盖原来的corePoolSize值,并且基于当前值和原始值的比较结果采取不同的处理策略。
对于当前值小于当前工作线程数的情况,说明有多余的worker线程,
此时会向当前空闲的worker线程发起中断请求以实现回收,
多余的worker在下次空闲的时候也会被回收;
对于当前值大于原始值且当前队列中有待执行任务,
则线程池会创建新的worker线程来执行队列任务,setCorePoolSize具体流程如下:
在这里插入图片描述

这篇关于线程池核心九问的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/335174

相关文章

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

详解MySQL中DISTINCT去重的核心注意事项

《详解MySQL中DISTINCT去重的核心注意事项》为了实现查询不重复的数据,MySQL提供了DISTINCT关键字,它的主要作用就是对数据表中一个或多个字段重复的数据进行过滤,只返回其中的一条数据... 目录DISTINCT 六大注意事项1. 作用范围:所有 SELECT 字段2. NULL 值的特殊处

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Java中常见队列举例详解(非线程安全)

《Java中常见队列举例详解(非线程安全)》队列用于模拟队列这种数据结构,队列通常是指先进先出的容器,:本文主要介绍Java中常见队列(非线程安全)的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一.队列定义 二.常见接口 三.常见实现类3.1 ArrayDeque3.1.1 实现原理3.1.2

SpringBoot3中使用虚拟线程的完整步骤

《SpringBoot3中使用虚拟线程的完整步骤》在SpringBoot3中使用Java21+的虚拟线程(VirtualThreads)可以显著提升I/O密集型应用的并发能力,这篇文章为大家介绍了详细... 目录1. 环境准备2. 配置虚拟线程方式一:全局启用虚拟线程(Tomcat/Jetty)方式二:异步

java中Optional的核心用法和最佳实践

《java中Optional的核心用法和最佳实践》Java8中Optional用于处理可能为null的值,减少空指针异常,:本文主要介绍java中Optional核心用法和最佳实践的相关资料,文中... 目录前言1. 创建 Optional 对象1.1 常规创建方式2. 访问 Optional 中的值2.1

如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socket read timed out的问题

《如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socketreadtimedout的问题》:本文主要介绍解决Druid线程... 目录异常信息触发场景找到版本发布更新的说明从版本更新信息可以看到该默认逻辑已经去除总结异常信息触发场景复

Java Jackson核心注解使用详解

《JavaJackson核心注解使用详解》:本文主要介绍JavaJackson核心注解的使用,​​Jackson核心注解​​用于控制Java对象与JSON之间的序列化、反序列化行为,简化字段映射... 目录前言一、@jsonProperty-指定JSON字段名二、@JsonIgnore-忽略字段三、@Jso