线程池面试问题

  • 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:一个由链表结构组成的双端阻塞队列,可以从队列的两端插入和删除元素。

线程池面试题灵魂三问相关推荐

  1. 金九银十:线程、多线程,线程池面试题十连问!

    点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 大家好我是小于哥啊,最近的面试中,关于线程.多线程,线程池相关的面试题还是挺多的.今天我 ...

  2. 线程池面试题一般会怎么问?线程池面试题总结及答案整理

    对于广大程序员来说,线程池一定不会陌生,因为大部分程序员面试时总会被问到关于线程池的问题,今天总结了一些关于线程池的各种面试可能问到的题目,希望对大家有所帮助. 一.线程池是什么? 答:线程池,是一种 ...

  3. 【算法面试题】带环链表之灵魂三问!

    文章目录 带环链表之灵魂三问! 一.判断链表是否有环 二.找出环的入口 三.计算环的长度 四.代码实现 带环链表之灵魂三问! 今天舍友二狗子又去面试了,回来就问我们算法问题,看来对于ios开发来说算法 ...

  4. java线程池面试题有哪些?java线程池常见面试题

    进行java面试的过程中,java线程池是必问的面试题目,因为这是java的重点知识,也是在java工作中经常会遇到的,那java线程池面试题有哪些?下面来我们就来给大家讲解一下java线程池常见面试 ...

  5. 关于联邦学习What、How、Who的灵魂三问

    最近沉迷于学习政治经济学无法自拔,听了很多资本论相关的课程.今天也尝试通过what how who的方式介绍下联邦学习, (感谢这个领域的专家,老同学Dr Liu给我的输入) 灵魂三问指的是: 1.联 ...

  6. 【新书速递】你想知道的通信“灵魂三问”都在这里……(福利再现)

    更多精彩内容请关注我们 来源丨知书通礼(ID:xintongzstl) 作者丨杨波 每次遇到刚入行又爱思考的年轻人,经常被问及有关通信的"灵魂三问". "通信是什么?&q ...

  7. 软件测试灵魂三问,如何回怼?

    灵魂三问: 第 1 问:为什么这个 Bug 测不出来? 第 2 问:测试怎么测得?到底会不会测? 第 3 问:测试快点啊!为什么总是测试拖后腿,最后才报 Bug? 有朋友说: 对测试新人则是" ...

  8. 数字化转型服务管理与VeriSM(1):灵魂三问

    正在上传-重新上传取消 最近,在与一些朋友探讨企业IT未来的治理和发展时,多次谈及"数字化时代"."数字化转型"等话题.昨天(3月19日)晚上,玥悉商务咨询有限 ...

  9. 通信人的“灵魂三问”,你知道答案吗?(文末有赠书福利)

    每一位通信人,都可能面对过来自亲友的"灵魂三问". "通信究竟是什么?" "通信从哪里来?" "通信要往哪里去?" 对于 ...

最新文章

  1. 时间序列:等分布序列(Equidistributed sequence)
  2. 2021-05-10 矩阵AB和矩阵BA有什么联系?
  3. Spring实战 MethodInvokingJobDetailFactoryBean使用与分析
  4. python奇偶求和_python 判断奇偶并求和,运行过程有错误,希望高手给指导一下。...
  5. 关于Outlook删除原邮箱邮件的解决办法
  6. mysql安装版卸载_MYSQL安装与卸载(一)
  7. DataBinding 学习系列(3)新增的可见字段来编写对象(bean)
  8. 语音识别入门:从菜鸟到大佬
  9. 用C#实现图片数据库存储与显示
  10. FFMPEG关键结构体
  11. html 头标签 meta http-equiv 属性应用。
  12. 自定义View在android2.3.3手机上正常运行 在android4.2.2手机上报空指针
  13. php 网贷 源码,thinkphp仿百度钱包网贷借款源码
  14. vlc 网页插件的 使用与控制 API
  15. Jpa是什么——Jpa使用详解
  16. Unity Driven 属性(代码控制属性)使用示例
  17. 常见Android智能手机通信录导入方法
  18. linux下如何避免rsyslog系统日志不停打印到console
  19. jar包过大?手把手教你分析Maven依赖,完美“瘦身”优化!
  20. 7z压缩软件dos命令

热门文章

  1. 社群经济与DBA+的2045年
  2. 基于ROS的Most Stars开源代码汇总(自动驾驶汽车+RGBDSLAMv2+ROS2+人识别与跟踪等)
  3. ESP8266开发之旅 阿里云物联网平台篇② MQTT.FX客户端模拟 调试 MQTT LED智能灯控制系统
  4. java行业认知报告_大学生专业认知报告(共10篇).docx
  5. 用SpringCloud搭建Rest风格的环境
  6. 关于keil 官网下载芯片包速度太慢的问题
  7. 怎么克隆Windows Server 2016系统到另一个硬盘?
  8. maven常见面试题
  9. 全网最全Android开发工具,Android开发框架大全
  10. 科技赋能智慧城市发展,京东方智慧物联解决方案亮相北京峰会