并发编程(三):线程池基本面试题(必背题目)

您所在的位置:网站首页 池上题目什么意思 并发编程(三):线程池基本面试题(必背题目)

并发编程(三):线程池基本面试题(必背题目)

2024-07-09 19:46| 来源: 网络整理| 查看: 265

目录

一、背景

二、高频面试题(八股文)

1、什么是线程池?线程池有什么好处(被问概率很小)?

2、有几种常见的线程池(必知必会)?

3、线程池的主要参数有哪些(必知必会)?

4、线程池的工作流程(必知必会)?

5、线程池的拒绝策略有哪些(必知必会)?

6、线程池有哪几种工作队列(被问概率:小于10%)?

7、如何合理设置线程池的核心线程数(必知必会)?

8、线程池异常是怎么处理的(被问概率很小)?

9、线程池优化了解吗(40%可能性被问到)?

10、你能设计实现一个线程池吗(BAT容易问到,小公司不会)?

三、参考文献

一、背景

金三银四话说是跳槽的最佳时机,各大公司也在此时招兵买马,当然面试者也很多,基本上一个面试官至少2场面试,而面试者也旗鼓相当,每天面2家的节奏。我本人也参加了一些公司的面试,发现线程池被问到的概率达到50%以上,而且问的问题大概就那几个,没啥新意。唯一有新意的是一个架构师问我“如何设计一个线程池”,虽然看过,但是没有理解,忘了!!!好记性不如烂笔头,还是记录下吧。

二、高频面试题(八股文) 1、什么是线程池?线程池有什么好处(被问概率很小)?

所谓线程池,通俗来讲,就是一个管理线程的池子。它可以容纳多个线程,其中的线程可以反复利用,省去了频繁创建线程对象的操作。 好处: 1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。 3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

2、有几种常见的线程池(必知必会)?

1)定长线程池(FixedThreadPool) 2)定时线程池(ScheduledThreadPool) 3)可缓存线程池(CachedThreadPool) 4)单线程化线程池(SingleThreadExecutor)

核心概念:这四个线程池的本质都是ThreadPoolExecutor对象(自己看源码) 不同点在于: 1)FixedThreadPool:只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列。 2)ScheduledThreadPool:核心线程数量固定,非核心线程数量无限,执行完闲置 10ms 后回收,任务队列为延时阻塞队列。 3)CachedThreadPool:无核心线程,非核心线程数量无限,执行完闲置 60s 后回收,任务队列为不存储元素的阻塞队列。 4)SingleThreadExecutor:只有 1 个核心线程,无非核心线程,执行完立即回收,任务队列为链表结构的有界队列

上面只是面试题目,除了面试之外想了解细节,看看这个文章: https://blog.csdn.net/u013541140/article/details/95225769

3、线程池的主要参数有哪些(必知必会)?

1)corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。 2)maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。 3)keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。 4)unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。 5)workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。 6)threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。 7)handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。

4、线程池的工作流程(必知必会)?

这个问题回答的时候,最好用讲故事的方式进行。 假如核心线程数是5,最大线程数是10,阻塞队列也是10 1)有新任务来的时候,将先使用核心线程执行; 2)当任务数达到5个的时候,第6个任务开始排队; 3)当任务数达到15个的时候,第16个任务将开启新的线程执行,也就是第6个线程 4)当任务数达到20个的时候,线程池满了,如果有第21个任务,将执行拒绝策略(见下一个问题) 流程图:

5、线程池的拒绝策略有哪些(必知必会)?

1)AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。 2)CallerRunsPolicy:由调用线程处理该任务。 3)DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。 4)DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

6、线程池有哪几种工作队列(被问概率:小于10%)?

1)ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列(数组结构可配合指针实现一个环形队列)。 2)LinkedBlockingQueue: 一个由链表结构组成的有界阻塞队列,在未指明容量时,容量默认为 Integer.MAX_VALUE。 3)PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现 Comparable 接口也可以提供 Comparator 来对队列中的元素进行比较。跟时间没有任何关系,仅仅是按照优先级取任务。 4)DelayQueue:类似于PriorityBlockingQueue,是二叉堆实现的无界优先级阻塞队列。要求元素都实现 Delayed 接口,通过执行时延从队列中提取任务,时间没到任务取不出来。 SynchronousQueue: 一个不存储元素的阻塞队列,消费者线程调用 take() 方法的时候就会发生阻塞,直到有一个生产者线程生产了一个元素,消费者线程就可以拿到这个元素并返回;生产者线程调用 put() 方法的时候也会发生阻塞,直到有一个消费者线程消费了一个元素,生产者才会返回。 5)LinkedBlockingDeque: 使用双向队列实现的有界双端阻塞队列。双端意味着可以像普通队列一样 FIFO(先进先出),也可以像栈一样 FILO(先进后出)。 6)LinkedTransferQueue: 它是ConcurrentLinkedQueue、LinkedBlockingQueue 和 7)SynchronousQueue 的结合体,但是把它用在 ThreadPoolExecutor 中,和 LinkedBlockingQueue 行为一致,但是是无界的阻塞队列。

7、如何合理设置线程池的核心线程数(必知必会)?

 线程数量的计算公式一般都是 线程数=Ncpu(1+w/e).其中W代表的是阻塞耗时,e代表的是计算耗时。 1)IO密集型:如果存在IO,那么W/e肯定大于1,但是需要考虑系统内存上限(没开启一个线程都需要内存空间),这个需要服务器测试到底多少个线程比较合适(CPU占比,线程数、总耗时、内存耗时)。保守取值为1,及线程数=2Ncpu+1, 2)计算密集型:假设没有等待时间,则W=0,W/C=0,线程数= Ncpu+1. 其中多出来的一个是为了防止线程偶发的缺页中断。服务性能I0优化有一个估算公式: 最佳线程数目=((线程等待时间+线程CPU时间)/线程CPU时间)X CPU数量 比如平均每个线程CPU运行时间为0.5s,而线程等待时间为1.5s(比如IO),CPU个数为8.则根据以上公式可以估算((1.5+0.5)/0.5)X 8=32 公式进一步转化: 最佳线程数目 = (线程等待时间/线程CPU时间+1)X 线程数 参考文献: https://www.cnblogs.com/loveLands/articles/10016170.html

8、线程池异常是怎么处理的(被问概率很小)?

由于几乎不被问到,所以不总结了,直接看这两篇文章吧:

1)一个线程池中的线程异常了,那么线程池会怎么处理这个线程? https://www.cnblogs.com/fanguangdexiaoyuer/p/12332082.html 2)【线程池】线程池的线程遇到异常后去哪里?怎么处理? https://blog.csdn.net/qfzhangwei/article/details/105181055

9、线程池优化了解吗(40%可能性被问到)?

这个问题和第7个问题很类似,可以参考回答。其他答案: 1)用ThreadPoolExecutor自定义线程池,看线程是的用途,如果任务量不大,可以用无界队列,如果任务量非常大,要用有界队列,防止OOM 2)如果任务量很大,还要求每个任务都处理成功,要对提交的任务进行阻塞提交,重写拒绝机制,改为阻塞提交。保证不抛弃一个任务 3)最大线程数一般设为2N+1最好,N是CPU核数 4)核心线程数,看应用,如果是任务,一天跑一次,设置为0,合适,因为跑完就停掉了,如果是常用线程池,看任务量,是保留一个核心还是几个核心线程数 5)如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取,如果在主线程获取,就要等任务都提交后才获取,就会阻塞大量任务结果,队列过大OOM,所以最好异步开个线程获取结果。

10、你能设计实现一个线程池吗(BAT容易问到,小公司不会)?

可以这样作答: 我们自己的实现就是完成这个核心流程: 1)线程池中有N个工作线程 2)把任务提交给线程池运行 3)如果线程池已满,把任务放入队列 4)最后当有空闲时,获取队列中任务来执行 具体的分析可以参考这篇文献: https://blog.csdn.net/dgutliangxuan/article/details/103642963

其他: 如果你想了解更多,建议阅读参考文献4(面渣逆袭:线程池夺命连环十八问),这篇文章总结的还是不错的。

三、参考文献

1、什么是线程池,线程池的作用 https://blog.csdn.net/weixin_50897975/article/details/119947495 2、Java 多线程:彻底搞懂线程池 https://blog.csdn.net/u013541140/article/details/95225769 3、线程池中如何确定线程的数目 https://www.cnblogs.com/loveLands/articles/10016170.html 4、面渣逆袭:线程池夺命连环十八问 https://blog.csdn.net/sinat_40770656/article/details/121370427 5、一个有趣的问题 : 如何设计一个线程池 https://blog.csdn.net/dgutliangxuan/article/details/103642963  



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3