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. 分析指标原因,评估策略,然后通过上述线程池提供的接口进行修改
相关推荐
白水先森1 分钟前
牵引线标注:让地图信息更清晰的ArcGIS Pro技巧
开发语言·javascript·经验分享·arcgis·arcgispro
筱涵哥5 分钟前
Python默认参数详细教程:默认参数位置错误,动态默认值,__defaults__属性,动态默认值处理,从入门到实战的保姆级教程
开发语言·python
sevevty-seven5 分钟前
Spring Boot 自动装配原理详解
java·spring boot·后端
Forget the Dream1 小时前
设计模式之迭代器模式
java·c++·设计模式·迭代器模式
咩咩觉主1 小时前
C# &Unity 唐老狮 No.7 模拟面试题
开发语言·unity·c#
大丈夫在世当日食一鲲1 小时前
Java中用到的设计模式
java·开发语言·设计模式
A-Kamen1 小时前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
练川2 小时前
Stream特性(踩坑):惰性执行、不修改原始数据源
java·stream
狂奔小菜鸡2 小时前
Java运行时数据区
java·jvm·后端
trymoLiu2 小时前
SpringBoot 实现 RSA+AES 自动接口解密!
java·spring boot