当前位置:网站首页>作为面试官,关于线程池的问题我一般这样套路...
作为面试官,关于线程池的问题我一般这样套路...
2022-07-31 09:04:00 【Java Punk】
大家好,我是一家不知名企业的知名工程师,除了负责后端开发任务,还要兼顾面试新人和培训新人的工作。在面试候选人的过程中,我比较倾向于问一些偏基础又较为开放的问题,用来看看候选人基础能力怎么样。比如今天要说的线程池。
把我的经验分先给大家,希望初学者既要注重基础,更要结合实践,多思考。
正文
一、引出问题
根据项目经验,我会先问候选人平时怎么使用线程池,得到的结果不出意外就是两种:
- 我不用线程池,工作中没接触过并发;
- 用Executors.newCachedThreadPool;
不管是哪一种回答,我还是希望能从候选人那里得到他们对线程池的理解,因此还是会问一下ThreadPoolExecutorService的几个参数相关的问题,除了基础非常差的候选人外,一般候选人都能回答上corePoolSize, maxPoolSize, BlockingQueue之间的关系:
- corePoolSize是核心线程数,maxPoolSize是最大线程数,BlockingQueue是任务队列
- 当有任务提交时,先创建corePoolSize数量的线程,有更多的任务则进入到BlockingQueue,BlockingQueue满了还不够则创建线程数直到macPoolSize
- 线程空闲一段时间后会被销毁直到线程池中只剩下core数量的线程;
二、基础部分
老生常谈的问题,还是要走一下流程的,一般人面试前都会准备,也是为了让候选人放松心态进入状态,比如问一下:
问题1:线程的状态以及状态之间的流转?
这个地方我希望候选人说的尽量具体一点,不仅要明确说出有哪些状态,还要扩展到进入状态的方法和区别。
- NEW – 尚未启动的线程处于此状态(创建线程对象);
- RUNNABLE – 在Java虚拟机中执行的线程处于此状态(start()开启线程);
- BLOCKED – 被阻塞等待监视器锁定的线程处于此状态(无法获得锁);
- WAITING – 正在等待另一个线程执行特定动作的线程处于此状态(wait()等待);
- TIMED_WAITING – 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态(sleep(long time)睡眠);
- TERMINATED – 已退出的线程处于此状态(线程执行完毕任务)。
问题2:在上述流程基础上,我还会延伸的问一下线程的终止和唤起方法?
1. 终止:shutdown()和shutdownNow()都是用来用来关闭线程的方法,区别在于:
- shutdown():“温柔”的关闭线程池。不接受新任务,但是在关闭前会将之前提交的任务处理完毕。
- shutdownNow():“粗暴”的关闭线程池,也就是直接关闭线程池,通过 Thread#interrupt() 方法终止所有线程,不会等待之前提交的任务执行完毕,但是会返回队列中未处理的任务。
2. 唤起:notify()和notifyAll()都是用来用来唤醒调用wait()方法进入等待锁资源队列的线程,区别在于:
- notify():唤醒正在等待此对象监视器的单个线程。 如果有多个线程在等待,则选择其中一个随机唤醒(由调度器决定),唤醒的线程享有公平竞争资源的权利;
- notifyAll():唤醒正在等待此对象监视器的所有线程,唤醒的所有线程公平竞争资源。
问题3:针对线程池满了以后,线程池的拒绝策略?
还是基础部分的考察,这样,整个现成的生命周期基本上算是考察完毕了。
- AbortPolicy:中止策略。默认的拒绝策略,直接抛出 RejectedExecutionException,调用者可以捕获这个异常,然后根据需求编写自己的处理代码;
- DiscardPolicy:抛弃策略。什么都不做,直接抛弃被拒绝的任务;
- DiscardOldestPolicy:抛弃最老策略。抛弃阻塞队列中最老的任务,相当于就是队列中下一个将要被执行的任务,然后重新提交被拒绝的任务。如果阻塞队列是一个优先队列,那么“抛弃最旧的”策略将导致抛弃优先级最高的任务,因此最好不要将该策略和优先级队列放在一起使用;
- CallerRunsPolicy:调用者运行策略。在调用者线程中执行该任务。该策略实现了一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将任务回退到调用者(调用线程池执行任务的主线程),由于执行任务需要一定时间,因此主线程至少在一段时间内不能提交任务,从而使得线程池有时间来处理完正在执行的任务。
三、实战部分
回答出线程池这几个参数的作用以及他们之间的关系后,我一般会给一到两个线程池相关的题,看看候选人是否能思考出,比如:
问题4:工作中,在什么场景下使用过线程处理业务?
这样的问题就很开放了,主动权完全交给候选人,但是这很考察候选人在项目开发过程中,有没有勤于思考的习惯还有代码优化的意识。为什么这么说呢?
先讲一下线程的使用场景,我总结了2个:阻塞和依赖。
- 阻塞:一旦系统中出现了阻塞现象,那么可以根据实际情况来使用多线程技术提高运行效率;比如:需要将几百万条数据落库,或者定时向几百万用户发送邮件通知,相比于传统的串行执行,多线程能提高效率。
- 依赖:业务分为两个执行过程A和B,当A业务发生阻塞或者延迟时,B业务的执行不依赖A业务的执行结果,也可以理解为异步操作;比如:做登录业务时使用sms短信网关业务,可以创建子线程,让子线程异步去调用sms服务,主线程则返回,这样做可以提高用户的体验度。
我最近还用到了一种异步的线程服务,就是使用 Guava Cache 的时候,启用子线程异步刷新 Cache 缓存,避免主线程查询时的阻塞。
针对候选人提供的业务场景,我们能做的事情也很多,可以把问题延伸到项目上,也可以继续聚焦线程本身再深挖一下实战应用,进一步考察候选人的线程设计能力:
问题5:假如提交到线程池中的任务,IO耗时占比是90%,计算耗时占比10%,忽略提交到线程池中的任务数量,在4C8G的机器上,理想情况下线程池中创建多少个线程是最优的?
一般平时只埋头写CURD的候选人,难以计算出来,当然也遇到了不少能算出来结果来的,线程数=(1/0.1) * 4 * 100% = 40。
强调一下:不管是那种公式算出来的结果,得出的都是理论数据,是参考值,具体线程数还要根据使用场景估算出用户量、并发量等数据,最后进行实际压测的结果为准。能说出这样的话会显得非常有严谨和经验。
然后,能算出来的候选人,我会问下其它问题,例如:
问题6:假如e有一类cpu密集性的任务,没有IO操作,日常的时候只有1个任务,流量高峰会有50个任务,4C8G的机器上,使用的线程池,如何设置corePoolSize, maxPoolSize以及BlockingQueue的大小?
这样的问题,我还没有遇到能回答的很完美的候选人,尤其是在面试紧张的情况下,一般得到类似于下的回答:
- corePoolSize=4个线程,maxPoolSize大点100个,队列大点,1万
- 2个线程,队列大点1千
- …
因此我会对候选人做一些引导,比如:回答core=4, max=50, queue=1w的,我会问他他设置的maxPoolSize有没有作用?明显队列设置成1w,这个队列太大,根本就不会满,maxPoolSize数量的线程永远不会被创建,说明候选人是随意设置的,没有经过思考,这个时间我会让他结合前面一个题再思考思考。
这一步后,有些等候人开始回答出用4个线程,队列50,但这样并不是最优的,因为日常每秒1个任务时,只需要一个线程就够了,创建出4个线程,就有3个浪费。
很显然:日常只需要一个线程,那么corePoolSize=1,而高峰时候,虽然任务有50个,但是只是4C的机器,对于cpu密集型任务,4个线程是最优的,因此理想情况下maxCorePoolSize=4,最后再看看队列,因为队列满了,max才会被创建,而我们需要让max快速被创建出来,又不会出现任务拒绝,因此,可将队列大小设置成46,那么线程池的行为如下:
- 提交第一个任务,创建出core,1个线程;
- 提交第二个到第47个任务时,这些任务进入到队列中,此时队列已满;
- 提交第48个任务到第50个任务时,创建出max,此时一共有4个线程;
- 此后不在创建新线程,4个线程同时将队列里的46个任务消费完;
- 一段时间后,max - core数量的线程销毁,即销毁3个线程,还剩下一个线程,资源最优。
问题7:......
差不多的了,多线程部分掌握到这里就可以了,留点时间问问其他的吧。
边栏推荐
猜你喜欢
随机推荐
高并发高可用高性能的解决方案
浏览器使用占比js雷达图
高并发-高可用-高性能
MySQL 排序
How to upgrade nodejs version
一、MySQL主从复制原理
一次Spark SQL线上问题排查和定位
[MySQL exercises] Chapter 3 Common data types in MySQL
postgresql 范围查询比索引查询快吗?
[Cloud native and 5G] Microservices support 5G core network
剑指offer-解决面试题的思路
如何升级nodejs版本
How on one machine (Windows) to install two MYSQL database
js右侧圆点单页滚动介绍页面
Andoird开发--指南针(基于手机传感器)
spark过滤器
Flink1.15 source code reading flink-clients - flink command line help command
Flink1.15源码阅读flink-clients——flink命令行帮助命令
【云原生与5G】微服务加持5G核心网
js部门预算和支出雷达图