线程池面试题灵魂三问
线程池面试问题
- 1、日常工作中有用到线程池吗?什么是线程池?为什么要使用线程池?
- 2、ThreadPoolExecutor都有哪些核心线程?
- 3、什么是阻塞队列?说说常用的阻塞队列?
1、日常工作中有用到线程池吗?什么是线程池?为什么要使用线程池?
计算机发展到现在,摩尔定律在现有工艺水平下已经遇到难以突破的物理瓶颈,通过多核CPU并行计算来提升服务器的性能已经成为主流,随之出现了多线程技术。
线程作为操作系统宝贵的资源,对它的使用需要进行管理控制,线程池就是采用池化思想(类似于连接池、常量池等)管理线程的工具。
Java的JUC包给我们提供了ThreadPoolExecutor体系类来帮助我们更加方便的管理线程、并行执行任务。
使用线程池的好处:
1、降低资源消耗。降低频繁创建、销毁线程带来的额外的开销,复用已经创建的线程。
2、降低使用复杂度。将任务的提交和执行进行解耦,我们只需要创建一个线程池,然后往里面提交任务即可,具体的执行流程由线程池自己管理,降低使用复杂度。
3、提高线程可管理性。能安全有效的管理线程资源,避免不加限制无限申请造成资源耗尽风险。
4、提高响应速度。任务到达后,直接复用已经创建好的线程执行。
线程池的使用场景简单的有:
1、快速响应用户需求,响应速度优先。比如一个用户请求,需要通过调用RPC调用好几个服务去获取数据然后聚合返回,此场景就可以用线程池进行调用,响应时间取决于响应最慢的那个RPC接口的耗时;又或者一个注册请求,注册完成之后要发送短信、邮件等通知,为了快速返回给用户信息,可以将该通知操作丢到线程池里异步执行,然后直接返回客户端成功信息,提高用户体验。
2、单位时间内处理更多请求,吞吐量优先。比如接收MQ消息,然后去调用第三方接口进行查询数据,此场景并不追求快速响应,主要利用有限的资源在单位时间内尽可能多的处理任务,可以利用队列进行任务的缓冲。
2、ThreadPoolExecutor都有哪些核心线程?
- 核心线程数(corePoolSize)
- 最大线程数(maximumPoolSize)
- 空闲线程超时时间(keepAliveTime)
- 时间单位(unit)
- 阻塞队列(workQueue)
- 拒绝策略(handler)
- 线程工厂(ThreadFactory)
execute()方法的执行流程:
1. 判断线程池的状态,如果不是RUNNING状态,直接执行拒绝策略
2. 如果当前线程数 < 核心线程池,则新建一个线程来处理提交的任务
3. 如果当前线程数 > 核心线程数且任务队列没满,则将任务放入阻塞队列等待执行
4. 如果 核心线程池 < 当前线程池数 < 最大线程数,且任务队列已满,则创建新的线程执行提交的任务
5. 如果当前线程数 > 最大线程数,且队列已满,则执行拒绝策略拒绝该任务
这个执行流程是JUC标准线程池提供的执行流程,主要用在CPU密集型场景下。
像Tomcat、Dubbo这类框架,它们内部的线程池主要用来处理网络IO任务的,所以它们都对JUC线程池的执行流程进行了调整来支持IO密集型场景使用。
它们提供了阻塞队列TaskQueue,该队列继承LinkedBlockingQueue,重写了offer()方法来实现执行流程的调整。
@Overridepublic boolean offer(Runnable o) {//we can't do any checksif (parent==null) return super.offer(o);//we are maxed out on threads, simply queue the objectif (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);//we have idle threads, just add it to the queueif (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);//if we have less threads than maximum force creation of a new threadif (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;//if we reached here, we need to add it to the queuereturn super.offer(o);}
这里的parent就是所属的线程池对象
1、如果 parent 为 null,直接调用父类 offer 方法入队
2、如果当前线程数等于最大线程数,则直接调用父类 offer()方法入队
3、如果当前未执行的任务数量小于等于当前线程数,仔细思考下,是不是说明有空闲的线程呢,那么直接调用父类 offer() 入队后就马上有线程去执行它
4、如果当前线程数小于最大线程数量,则直接返回 false,然后回到 JUC 线程池的执行流程回想下,是不是就去添加新线程去执行任务了呢
5、其他情况都直接入队
可以看出当当前线程数大于核心线程数时,JUC 原生线程池首先是把任务放到队列里等待执行,而不是先创建线程执行。
如果 Tomcat 接收的请求数量大于核心线程数,请求就会被放到队列中,等待核心线程处理,这样会降低请求的总体响应速度。
所以 Tomcat并没有使用 JUC 原生线程池,利用 TaskQueue 的 offer() 方法巧妙的修改了 JUC 线程池的执行流程,改写后 Tomcat 线程池执行流程如下:
1、判断如果当前线程数小于核心线程池,则新建一个线程来处理提交的任务
2、如果当前当前线程池数大于核心线程池,小于最大线程数,则创建新的线程执行提交的任务
3、如果当前线程数等于最大线程数,则将任务放入任务队列等待执行
4、如果队列已满,则执行拒绝策略
线程池的 Worker 线程模型,继承 AQS 实现了锁机制(空闲时可以响应中断,在执行任务时不可被中断)。线程启动后执行 runWorker() 方法,runWorker() 方法中调用 getTask() 方法从阻塞队列中获取任务,获取到任务后先执行 beforeExecute() 钩子函数,再执行任务,然后再执行 afterExecute() 钩子函数。若超时获取不到任务会调用 processWorkerExit() 方法执行 Worker 线程的清理工作。
3、什么是阻塞队列?说说常用的阻塞队列?
阻塞队列BlockingQueue继承Queue,是我们常用的基本数据结构队列的一种特殊类型。
当从阻塞队列中获取数据时,如果队列为空,则等待直到队列有元素存入。当阻塞队列中存入元素时,如果队列已满,则等待队列中直到有元素被移除。提供队列常用方法offer()、put()、take()、poll()等方法。
JDK提供的阻塞队列的实现有以下几种:
(1)ArrayBlockingQueue:由数组实现的有界阻塞队列,该队列按照FIFO对元素进行排序。维护两个整型数组,标识队列头尾在数组中的位置,在生产者放入和消费者获取数据公用的一个锁对象(ReentrantLock,每次操作需要手动加锁和手动释放锁),意味着两者无法真正的并行运行,性能较低。
(2)LinkedBlockingQueue:由链表组成的有界阻塞队列,如果不指定大小,默认使用Integer.MAX_VALUE作为队列大小,该队列按照FIFO对元素进行排序,对生产者和消费者分别维护了独立的锁来控制数据同步,意味着该队列有着更高的并发性能。(分别使用了takeLock和putLock来维护不同的操作)
(3)SynchronousQueue:不存储元素的阻塞队列,无容量,可以设置公平或者非公平模式,插入操作必须等待获取操作移除元素,反之亦然。
(4)PriorityBlockingQueue:支持优先队列的无界阻塞队列,默认情况下根据自然序排序,也可以指定Comparator。
(5)DelayQueue:支持延时获取元素的无界阻塞队列,创建元素时可以指定多久之后才能从队列中获取元素,常用于缓存系统或者定时任务调度系统。
(6)LinkedTransferQueue:一个由链表结构组成的无界阻塞队列,与LinkedBlockingQueue相比多了transfer和tryTranfer方法,该方法在有消费者等待接收元素时会立即将元素传递给消费者。
(7)LinkedBlockingDeque:一个由链表结构组成的双端阻塞队列,可以从队列的两端插入和删除元素。
线程池面试题灵魂三问相关推荐
- 金九银十:线程、多线程,线程池面试题十连问!
点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 大家好我是小于哥啊,最近的面试中,关于线程.多线程,线程池相关的面试题还是挺多的.今天我 ...
- 线程池面试题一般会怎么问?线程池面试题总结及答案整理
对于广大程序员来说,线程池一定不会陌生,因为大部分程序员面试时总会被问到关于线程池的问题,今天总结了一些关于线程池的各种面试可能问到的题目,希望对大家有所帮助. 一.线程池是什么? 答:线程池,是一种 ...
- 【算法面试题】带环链表之灵魂三问!
文章目录 带环链表之灵魂三问! 一.判断链表是否有环 二.找出环的入口 三.计算环的长度 四.代码实现 带环链表之灵魂三问! 今天舍友二狗子又去面试了,回来就问我们算法问题,看来对于ios开发来说算法 ...
- java线程池面试题有哪些?java线程池常见面试题
进行java面试的过程中,java线程池是必问的面试题目,因为这是java的重点知识,也是在java工作中经常会遇到的,那java线程池面试题有哪些?下面来我们就来给大家讲解一下java线程池常见面试 ...
- 关于联邦学习What、How、Who的灵魂三问
最近沉迷于学习政治经济学无法自拔,听了很多资本论相关的课程.今天也尝试通过what how who的方式介绍下联邦学习, (感谢这个领域的专家,老同学Dr Liu给我的输入) 灵魂三问指的是: 1.联 ...
- 【新书速递】你想知道的通信“灵魂三问”都在这里……(福利再现)
更多精彩内容请关注我们 来源丨知书通礼(ID:xintongzstl) 作者丨杨波 每次遇到刚入行又爱思考的年轻人,经常被问及有关通信的"灵魂三问". "通信是什么?&q ...
- 软件测试灵魂三问,如何回怼?
灵魂三问: 第 1 问:为什么这个 Bug 测不出来? 第 2 问:测试怎么测得?到底会不会测? 第 3 问:测试快点啊!为什么总是测试拖后腿,最后才报 Bug? 有朋友说: 对测试新人则是" ...
- 数字化转型服务管理与VeriSM(1):灵魂三问
正在上传-重新上传取消 最近,在与一些朋友探讨企业IT未来的治理和发展时,多次谈及"数字化时代"."数字化转型"等话题.昨天(3月19日)晚上,玥悉商务咨询有限 ...
- 通信人的“灵魂三问”,你知道答案吗?(文末有赠书福利)
每一位通信人,都可能面对过来自亲友的"灵魂三问". "通信究竟是什么?" "通信从哪里来?" "通信要往哪里去?" 对于 ...
最新文章
- 时间序列:等分布序列(Equidistributed sequence)
- 2021-05-10 矩阵AB和矩阵BA有什么联系?
- Spring实战 MethodInvokingJobDetailFactoryBean使用与分析
- python奇偶求和_python 判断奇偶并求和,运行过程有错误,希望高手给指导一下。...
- 关于Outlook删除原邮箱邮件的解决办法
- mysql安装版卸载_MYSQL安装与卸载(一)
- DataBinding 学习系列(3)新增的可见字段来编写对象(bean)
- 语音识别入门:从菜鸟到大佬
- 用C#实现图片数据库存储与显示
- FFMPEG关键结构体
- html 头标签 meta http-equiv 属性应用。
- 自定义View在android2.3.3手机上正常运行 在android4.2.2手机上报空指针
- php 网贷 源码,thinkphp仿百度钱包网贷借款源码
- vlc 网页插件的 使用与控制 API
- Jpa是什么——Jpa使用详解
- Unity Driven 属性(代码控制属性)使用示例
- 常见Android智能手机通信录导入方法
- linux下如何避免rsyslog系统日志不停打印到console
- jar包过大?手把手教你分析Maven依赖,完美“瘦身”优化!
- 7z压缩软件dos命令
热门文章
- 社群经济与DBA+的2045年
- 基于ROS的Most Stars开源代码汇总(自动驾驶汽车+RGBDSLAMv2+ROS2+人识别与跟踪等)
- ESP8266开发之旅 阿里云物联网平台篇② MQTT.FX客户端模拟 调试 MQTT LED智能灯控制系统
- java行业认知报告_大学生专业认知报告(共10篇).docx
- 用SpringCloud搭建Rest风格的环境
- 关于keil 官网下载芯片包速度太慢的问题
- 怎么克隆Windows Server 2016系统到另一个硬盘?
- maven常见面试题
- 全网最全Android开发工具,Android开发框架大全
- 科技赋能智慧城市发展,京东方智慧物联解决方案亮相北京峰会