Java线程池面试题

为什么要用线程池

  • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗
  • 提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行
  • 方便管理线程:线程是稀缺资源,如果无条件地创建,不仅会消耗资源,还会降低线程的稳定性,使用线程池可以统一分配、调优和监考。

线程池的核心参数

  • corePoolSize:核心线程的数量
  • maximumPoolSize:线程池能创建的最大线程个数
  • keepAliveTime:空闲线程存活时间
  • unit:时间单位
  • workQueue:用于保存任务的阻塞队列
  • threadFactory:创建线程的工程类
  • hadler:饱和策略

常见线程池的区别以及特点

CachedThreadPool:

  • 特点:newCachedThreadPool创建一个可缓存的线程池,如果当前线程池的长度超过了处理的需要,它可以灵活的回收空闲的线程,当需要添加的时候可以灵活的添加
  • 缺点:maximumPoolSize被设置为Inter.MAX_VALUE,可能会造成OOM

FixedThreadPool:

  • 特点:创建一个定长的线程池,可控制线程最大并发数,超出的任务会在线程中等待。
  • 缺点:线程数量是固定的,但是阻塞队列是LinkedBlockingQueue,是无界队列,也可能会造成OOM

ScheduledThreadPool:

  • 特点:创建一个固定长度的线程,而且支持定时的以及周期性的任务执行,类似Timer
  • 缺点:底层封装了PriorityQueue,同样是无界队列,可能会造成OOM

SingleThreadExecutor:

  • 特点:单线程化的线程池,它会用唯一的工作线程来执行任务。如果这个线程因为异常结束,那么会有一个新的线程来替代它。它必须保证前一项任务完成才能执行后一项。
  • 缺点:因为是单线程,高并发下有压力

为什么我们不用Executors默认创建线程池的方法,而直接自己手动去调用ThreadPoolExecutor去创建线程池

Executors 返回的线程池对象的弊端如下:

1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

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

线程池的饱和策略有哪些

  • ThreadPoolExecutor.AbortPolicy:抛出RejectedExecutionException来拒绝任务的处理
  • ThreadPoolExecutor.CallerRunsPolicy:调用提交任务的线程运行任务(比如A提交线程,A运行任务)。但是会降低新任务提交速度,影响程序的整体性能。
  • ThreadPoolExecutor.DiscardPolicy:不处理新任务,直接丢弃掉
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃掉最早的未处理的任务

线程池执行原理

  • 判断线程池的核心线程数是不是已满,如果不是则创建一个新的工作线程来执行任务。
  • 如果核心线程数已满,则将提交的任务放在保存任务的阻塞队列中。
  • 如果工作任务队列满了,则创建一个新的线程来执行任务,直到数量到达maximumPoolSize
  • 最后如果达到线程池最大线程数,则采取对应的饱和策略

线程池中submit()和 execute()方法有什么区别

相同点:

  • 都可以提交任务到线程池中

不同点

  • 接受参数:submit只能执行Runnable类型的任务,submit可以执行Runnable和Callable类型的任务
  • 返回值:submit方法可以返回持有计算结果的Future对象,而execute没有
  • 异常处理:submit可以方便处理异常

Java中Executor、Executors和ExecuteService的区别

  • Executor是最基本的接口,只定义了一个execute方法
  • ExecuteService是一个高级的接口,实现了Executor并进行了扩展,比如实现了submit方法。这个接口的目的是方便我们使用底层不同的线程池,类似List接口,屏蔽底层差异。
  • Executors是一个工具类,使用这个工具类可以方便的创建线程。让我们可以不用手动地指定线程池的各个参数,比如Executors.newFixedThreadPool(10);

线程池有哪些状态

  • Running:正常状态,可以接受其他线程
  • Shutdown:不接受新的任务提交,但是会继续处理等待队列中的任务
  • Stop:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程
  • Tidying:所有的任务都销毁,workerCount(线程数量)为0,线程池在向Tidying状态转换时,会执行钩子方法terminated()
  • Terminated:terminated()方法介绍后,就会变成这个

如何合理分配线程池大小

  • CPU密集型,任务可以少配置数,大概和CPU核数相当,这样可以使得每个线程在执行任务
  • IO密集型,大部分线程在阻塞,故需要多配置线程数,2 * cpu核数

线程池如何实现动态修改

线程池提供了部分setter方法可以设置线程池的参数:

  • 修改线程数,最大线程数,空闲线程停留时间,拒绝策略等
  • 可以将线程池的配置参数放入配置中心,然后直接在配置中心修改

什么时候需要修改?

  1. 需要监考报警策略,获取线程池状态指标,当指标判定为异常后再报警
  2. 分析指标原因,评估策略,然后通过上述线程池提供的接口进行修改
相关推荐
李匠20245 分钟前
C++GO语言微服务和服务发现②
开发语言·c++·golang·服务发现
bing_1589 分钟前
Spring MVC 中Model, ModelMap, ModelAndView 之间有什么关系和区别?
java·spring·mvc
每次的天空19 分钟前
Kotlin 内联函数深度解析:从源码到实践优化
android·开发语言·kotlin
2685725927 分钟前
JVM 监控
java·开发语言·jvm
promise52428 分钟前
JVM之jcmd命令详解
java·linux·运维·服务器·jvm·bash·jcmd
曼岛_36 分钟前
[Java实战]Spring Boot 静态资源配置(十三)
java·开发语言·spring boot
篱笆院的狗37 分钟前
MySQL 中如何进行 SQL 调优?
java·sql·mysql
m0_6161884941 分钟前
使用vue3-seamless-scroll实现列表自动滚动播放
开发语言·javascript·ecmascript
qq_433554541 小时前
C++ STL编程 vector空间预留、vector高效删除、vector数据排序、vector代码练习
开发语言·c++
随风奔跑的十八岁1 小时前
java 破解aspose.words 18.6 使用
java·linux·word转pdf·aspose-words