news 2026/4/16 9:19:39

Java线程池八股及实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java线程池八股及实现

线程池的八股

1、说一下线程池的核心参数?

ThreadPoolExecutor线程池的核心参数有7个,1.核心线程数目(corePoolSize)、2.最大线程数目(maximumPoolSize),最大线程数目=核心线程+临时线程、3.生存时间(keepAliveTime),是临时线程的生存时间,生存时间内没有新任务,临时线程会释放、4.时间单位(unit)、5.阻塞队列(workQueue),当核心线程满了之后新来的任务会进入队列排队,队列满后会创建临时线程执行任务、6.线程工厂(threadFactory),定制线程对象的创建,例如设置线程名字,是否是守护线程等、7.拒绝策略(handler),当所有线程都在忙,workQueue也放满时,就会触发拒绝策略。

2、线程池的执行原理?

首先提交任务会判断核心线程是否已满,如果没满就正常工作,如果已满的话就会判断这个阻塞队列是否已满,如果阻塞队列没满就放入阻塞队列等待,如果阻塞队列也满了,就判断线程数是否小于最大线程数,如果小于就创建临时线程,这时临时线程默认是来执行新来的任务,而不是执行从阻塞队列中取出的任务来执行,如果不小于,那就走拒绝策略。

3、拒绝策略有哪些?

拒绝策略有4种,1.AbortPolicy,直接抛异常,默认策略。2.CallerRunsPolicy,使用调用者所在线程来执行任务,如主线程main。3.DiscardOldestPolicy,丢弃阻塞队列最靠前的任务,来执行当前任务。4.DiscardPolicy,直接丢弃任务。

4、线程池中有哪些常见的阻塞队列?

有4种常见的阻塞队列,1.ArrayBlockingQueue,基于数组的有界阻塞队列,FIFO。2.LinkedBlockingQueue,基于链表的有界阻塞队列,FIFO。3.DelayedWorkQueue,优先级阻塞队列,保证每次出任务的是执行时间最靠前的任务。4.SynchronousQueue,不存储元素的阻塞队列,每次插入操作都要等待一个移除操作。

5、ArrayBlockingQueueLinkedBlockingQueue有什么区别?

LinkedBlockingQueue默认是无界的,支持有界,ArrayBlockingQueue强制有界。LinkedBlockingQueue底层是链表,ArrayBlockingQueue底层是数组。LinkedBlockingQueue是懒惰的,创建节点时添加数据,入队会生成新Node,ArrayBlockingQueue是提前初始化Node数组,Node需要是提前创建好的。LinkedBlockingQueue是两把锁,链表的头和尾加锁,ArrayBlockingQueue是全部一把锁,一般平时常用的就是LinkedBlockingQueue。

6、如何确定核心线程数?

分IO密集型任务和CPU密集型任务,注:N为CPU核数。如果并发不高、执行时间长的话,设置为IO密集型任务核心线程数就是2N+1;设置为CPU密集型任务核心线程数就是N+1。如果高并发、任务执行时间短的话核心线程数就是N+1,减少线程上下文切换。

7、线程池的种类有哪些?

常见的有4种,1.创建使用固定线程数的线程池,就是核心线程数和最大线程数一样,没有临时线程,阻塞队列是LinkedBlockingQueue。2.单线程化的线程池,核心线程数和最大线程数都是1,阻塞队列是LinkedBlockingQueue。3.可缓存线程池,核心线程数为0,只有临时线程数,阻塞队列是SynchronousQueue,不存储元素的阻塞队列,每次插入操作都要等待一个移除操作。3.提供了“延迟”和“周期执行”功能的ThreadPoolExecutor,可以执行延迟任务的线程池,支持定时及周期性完成任务。

8、为什么不建议使用Executors创建线程池?

可能会堆积大量的请求,创建大量的对象,导致OOM(内存溢出)。

9、谈谈你对ThreadLocal的理解?

为每个线程都分配一个独立的线程副本,让多个线程只操作自己内部的值,解决了并发访问冲突问题,同时实现了线程内的资源共享。

10、你知道ThreadLocal内存泄露问题吗?

线程内都维护了ThreadLocalMap成员变量,用来存储资源对象,调用set()方法,以ThreadLocal作为key,资源对象作为value,放入ThreadLocalMap集合中,然后调用get()方法到线程中查找自己key关联的资源。然后呢,ThreadLocal有用到弱引用和强引用,弱引用的内存会被回收,而强引用不会被回收,积累满了就可能发生内存泄露问题,可以使用remove()移除当前线程资源来解决内存泄露问题。

线程池的实现

配置类:

@Configuration public class ThreadPoolExecutorConfig { @Bean public ThreadPoolExecutor threadPoolExecutor() { // 创建线程工厂 ThreadFactory threadFactory = new ThreadFactory() { // 初始化线程数为1 private int count =1; @Override public Thread newThread(@NotNull Runnable r) { Thread thread = new Thread(r); thread.setName("线程" + count); count++; return thread; } }; return new ThreadPoolExecutor(2, 3, 1000, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), threadFactory); } }

演示线程池工作流程(核心线程数:2;最大线程池:3;阻塞队列可存放任务:4):

/** * 线程池队列测试接口 */ @RestController @RequestMapping("/queue") @Slf4j public class QueueController { @Resource private ThreadPoolExecutor threadPoolExecutor; // 核心线程数:2;最大线程池:3;阻塞队列可存放任务:4 @GetMapping("/add") public void add(String taskName){ // 创建任务 CompletableFuture.runAsync(()->{ log.info("当前线程:" + Thread.currentThread().getName() + "," + "正在执行任务" + taskName); try { Thread.sleep(1000000); } catch (InterruptedException e) { throw new RuntimeException(e); } },threadPoolExecutor); } @GetMapping("/get") public String get(){ Map<String, Object> map = new HashMap<>(); long taskCount = threadPoolExecutor.getTaskCount(); map.put("任务总数", taskCount); long completedTaskCount = threadPoolExecutor.getCompletedTaskCount(); map.put("已完成任务数", completedTaskCount); int activeCount = threadPoolExecutor.getActiveCount(); map.put("正在执行任务的线程数", activeCount); int size = threadPoolExecutor.getQueue().size(); map.put("队列长度", size); return JSONUtil.toJsonStr(map); } }

首先获取到当前状态情况:

以此类推发送任务2后执行情况如下:

两个核心线程占满,按预期接着发送任务应该放到队列中,队列长度+1:

因为我们阻塞队列可以存放4个任务,以此类推发满4个队列长度后再看看效果:

发送到任务7,也就是阻塞队列占满4个后再发送一个任务:

任务总数为7,队列长度依旧为4,可以发现临时线程默认是来执行新来的任务,而不是执行从阻塞队列中取出的任务来执行。

接着再发送一个任务,由于当前线程数=最大线程数,并且队列也满,预期应该是走默认拒绝策略:

符合预期。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/7 9:31:10

亲测Qwen-Image-Layered,图像分层编辑效果惊艳

亲测Qwen-Image-Layered&#xff0c;图像分层编辑效果惊艳 你有没有试过想把一张照片里的人换件衣服&#xff0c;却把背景也糊掉了&#xff1f;或者想给商品图换个质感背景&#xff0c;结果边缘毛边、光影不自然&#xff0c;反复修图半小时还像贴纸&#xff1f;传统AI修图工具…

作者头像 李华
网站建设 2026/4/15 5:48:47

5个维度解析B站视频下载工具:从需求到精通的完整指南

5个维度解析B站视频下载工具&#xff1a;从需求到精通的完整指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/bi…

作者头像 李华
网站建设 2026/4/13 5:45:15

为什么推荐科哥版Emotion2Vec+?这几点太贴心了

为什么推荐科哥版Emotion2Vec&#xff1f;这几点太贴心了 语音情感识别不是新鲜概念&#xff0c;但真正能“开箱即用、不踩坑、不折腾”的系统却不多。Emotion2Vec Large本身是阿里达摩院在ModelScope开源的高质量语音情感模型&#xff0c;而科哥在此基础上做的二次开发镜像—…

作者头像 李华
网站建设 2026/4/16 8:09:01

BilibiliDown音频提取完全指南:高质量音乐下载与管理方案

BilibiliDown音频提取完全指南&#xff1a;高质量音乐下载与管理方案 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirror…

作者头像 李华
网站建设 2026/4/15 9:12:06

宝可梦游戏定制:用pkNX打造专属冒险世界

宝可梦游戏定制&#xff1a;用pkNX打造专属冒险世界 【免费下载链接】pkNX Pokmon (Nintendo Switch) ROM Editor & Randomizer 项目地址: https://gitcode.com/gh_mirrors/pk/pkNX 作为宝可梦训练师&#xff0c;你是否曾幻想过拥有一只会喷火的皮卡丘&#xff1f;或…

作者头像 李华