Java线程池 面试考点
1. 线程池的好处
- 降低资源消耗:通过重复利用已创建的线程避免频繁创建和销毁线程(费时且消耗内存等系统资源)
- 提高响应速度:当任务提交时,可以不用等待创建进程就能立即执行
- 提高线程的可管理性:使用线程池可以对线程进行统一分配、调优和监控,更利于线程管理
2. 线程的工作流程
- 如果没有,则即使有空闲线程,也会创建线程来执行新的任务;
- 如果已经达到corePoolSize,则进行下一步。
- 如果没有满,则将新提交的任务加入工作队列;
- 如果满了,则进行下一步。
- 如果没有达到,就创建一个线程来执行新的任务;
- 如果达到了,就执行拒绝策略
3. 线程池的重要参数
- corePoolSize:线程池的基本大小,也是核心线程数量。在allowCoreThreadTimeOut==true的情况下,会维持这个数量的线程;
- maximumPoolSize:线程池中允许的最大线程数,线程池中的线程数量不能超过这个值。
- keepAliveTime:线程数量超过corePoolSize时,空闲线程的存活时间
- unit:keepAliveTime的时间单位
- workQueue:任务队列,被提交但尚未被执行的任务
- threadFactory:线程工厂,用来创建线程
- handler:拒绝策略
4. 拒绝策略
- AbortPolicy:直接抛出异常
- CallerRunsPolicy:由调用者线程(提交此任务的线程)执行这个任务0;【谁提交谁执行】;显然,提交任务的线程的性能极有可能会急剧下降;
- DiscardOldestPolicy:丢弃等待队列最前面的任务,然后重新提交被拒绝的任务;
- DiscardPolicy:丢弃掉,不处理。
5. JDK中线程池的类型
5.1 主要参数设置
类型 | corePoolSize | maximumPoolSize | keepAliveTime | workQueue | |
---|---|---|---|---|---|
newFixedThreadPool | nThreads | nThreads | 0 | LinkedBlockingQueue | 无界队列 |
newSingleThreadExecutor | 1 | 1 | 0 | LinkedBlockingQueue | 无界队列 |
newCachedThreadPool | 0 |
Integer.MAX_VALUE
|
60S | SynchronousQueue | 没有容量的队列 |
5.2 主要特点
FixedThreadPool
流程:
(1)如果当前正在执行任务的线程数少于corePoolSize,则创建新的线程来执行任务。
(2)如果当前正在执行任务的线程数等于corePoolSize,则将任务加入LinkedBlockingQueue。
(3)(1)中执行完任务的线程,会在循环中反复从LinkedBlockingQueue获取任务来执行。
FixedThreadPool使用无界队列LinkedBlockingQueue作为工作队列,这将会对线程池带来如下影响:
(1)线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池中的线程数不会超过corePoolSize。
(2)由于(1),线程池的maximumPoolSize和keepAliveTime将是无效参数,即不会被用到。
(3)由于使用无解队列,运行中的线程池不会执行决绝策略。
SingleThreadExecutor是FixedThreadPool的特例
CachedThreadPool
特点:
(1)由于corePoolSize为0,且keepAliveTime为60s,所以长时间没有任务提交时,线程池中无线程。
(2)SynchronousQueue没有容量,不能保存任务,所以每次提交任务,要么使用已有的空闲线程执行,要么创建新的线程执行。
(3)由于maximumPoolSize为无穷,所以可以一直创建新的线程,不执行拒绝策略。
(4)空闲的线程,等待60s没有收到新任务,将会终止。如果等待期间收到新任务,将会执行此任务。
(5)如果有大量的任务被提交,而且任务的提交速度高于任务的执行速度,那么线程池会开启等量的线程进行处理,这样可能会很快耗尽系统资源。
5.3 适用的场景
FixedThreadPool:因为线程数不会超过corePoolSize,所以适用于负载较重的场景,对当前线程数量进行限制
SingleThreadExecutor:线程池中只有一个线程,适用于需要保证顺序执行各个任务
CachedThreadPool:线程池可以无限扩大,适用于负载较轻的场景,执行短期异步任务
ScheduledThreadPool:适用于执行延时或者周期性任务
5.4 向线程池提交任务( execute()和submit() )
execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。
submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future.get()方法来获取返回值。get()会阻塞当前线程(即调用future.get()的线程)直到任务执行完成。而get(long timeout,TimeUnit unit)方法会阻塞一点时间后返回,此时任务可能还没有执行完。
6. 自定义线程池
想要合理地配置线程池,需要从任务特性和硬件条件两个方面考虑
6.1 任务特性
- 根据任务的性质来分:CPU 密集型任务、IO 密集型任务、混合型任务
- 根据任务的优先级:高、中、低
- 根据任务的执行时间:长、中、短
CPU 密集型任务应配置尽量小的线程池,如线程数为N+1,因为线程多了会造成频繁的线程上下文切换。(N为CPU数量)
IO 密集型任务在IO时不占用CPU,其线程不会一直执行任务,应配置尽可能多的线程,不要让CPU空闲,如2N+1。
混合型的话,如果可以,将其拆分为 IO 密集型和 CPU 密集型分别处理,前提是两者运行的时间是差不多的,如果处理时间相差很大,则没必要拆分了。
优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理,会让优先级高的任务先执行。
执行时间不同的任务,可以交给不同规模的线程池来处理
问题:高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?
(1)高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换
(2)并发不高、任务执行时间长的业务要区分开看:
a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务
b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
(3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。
6.2 硬件条件
CPU数量、内存大小、网络状况等
6.4 估算公式
佳线程数量 = ((线程等待时间+线程CPU时间)/ 线程CPU时间)* CPU个数
线程等待时间所占比例越高,需要越多的线程。
线程CPU时间所占比例越高,所需的线程数越少。
Java线程池 面试考点相关推荐
- Java 线程池 8 大拒绝策略,面试必问!
点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:KL博客 kailing.pub/article/index/arcid/255.h ...
- 面试必问---Java线程池8大拒绝策略
前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...
- 面试官问你Java线程池--怎么样回答才能让面试官知道你真的懂了!
一.引言 不管是Java面试还是Android面试,线程池都是面试官高频考察的点,那我们怎么回答,才能让面试官了解到我们是真的懂Java线程池了呢?这篇文章不涉及到线程池的使用和原理,如果你还不知道怎 ...
- Java面试系列之并发编程专题-Java线程池灵魂拷问
金三银四跳槽季即将来临,想必有些猿友已经蠢蠢欲动在做相关的准备了!在接下来的日子里,笔者将坚持写作.分享Java工程师在面试求职期间的方方面面,包括简历制作.面试场景复现.面试题解答.谈薪技巧 以及 ...
- java线程池_Java 线程池 8 大拒绝策略,面试必问!
点击上方 Java后端,选择设为星标 技术博文,及时送达 前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的 ...
- Java多线程系列(三):Java线程池的使用方式,及核心运行原理
之前谈过多线程相关的4种常用Java线程锁的特点,性能比较.使用场景,今天主要分享线程池相关的内容,这些都是属于Java面试的必考点. 为什么需要线程池 java中为了提高并发度,可以使用多线程共同执 ...
- Java 线程池必知的8 大拒绝策略
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | kailing.pub/article/ind ...
- java线程池的使用例子,不愧是大佬
京东Java研发岗一面(基础面,约1小时) 自我介绍,主要讲讲做了什么和擅长什么 springmvc和spring-boot区别 @Autowired的实现原理 Bean的默认作用范围是什么?其他的作 ...
- java线程池队列场景,Java面试题汇总
01 并发宝典:面试专题 面试专题分为四个部分,分别如下 Synchronized 相关问题 可重入锁 ReentrantLock 及其他显式锁相关问题 Java 线程池相关问题 Java 内存模型相 ...
- Java线程池(Executor)详解和用法
背景 面试的时候经常会被三连问.用过吗?如何用的?场景是什么?所以有必要好好的研究下线程池迫在眉睫. 1.讲解之前先了解下 retry: 因为源码中有这个retry标记 先看一个简单的例子 /*** ...
最新文章
- 扎克伯格AR野心:下个十年,远程「闪现」,不出家门跑到朋友家聊天
- 做一个略调皮的个人主页--相册与随笔篇
- stream的filter用法
- oracle元字符,正则表达式元字符
- Linux下scp命令的用法
- CentOS7.6下安装Ambari
- 【二分+二维前缀和】Largest Allowed Area
- 在一个热图中使用多个颜色主题
- linux脚本定时运行脚本,linux定时运行命令脚本——crontab
- 2018最有影响力的CRM系统排行榜
- linux系统调用使用方法,Linux系统的使用以及系统调用的开发方法OS.ppt
- dx 汇编dec_汇编语言算术指令
- 《东周列国志》第十九回 擒傅瑕厉公复国 杀子颓惠王反正
- Android工作日志
- php图片上传为base64,php实现base64图片上传方式实例代码
- 网络技术领域专业术语解释大全-170个术语
- 《点燃我,温暖你》李峋 代码 爱心❤ - 源代码
- 项目启动找不到资源文件可能的解决办法
- 秒杀刘海屏,有望实现手机|平板|电脑三合一,可折叠屏幕究竟是何方神圣?
- Java 手机号中间四位隐藏 MySQL函数手机号四位隐藏 Oracle手机号隐藏Java手机号码隐藏