1. 线程池的好处

  • 降低资源消耗:通过重复利用已创建的线程避免频繁创建和销毁线程(费时且消耗内存等系统资源)
  • 提高响应速度:当任务提交时,可以不用等待创建进程就能立即执行
  • 提高线程的可管理性:使用线程池可以对线程进行统一分配、调优和监控,更利于线程管理

2. 线程的工作流程

当提交一个新的任务到线程池时,线程池的处理流程如下:
step1. 判断线程池中正在执行任务的线程数是否达到corePoolSize。
  • 如果没有,则即使有空闲线程,也会创建线程来执行新的任务;
  • 如果已经达到corePoolSize,则进行下一步。
step2. 判断工作队列是否已满。
  • 如果没有满,则将新提交的任务加入工作队列;
  • 如果满了,则进行下一步。
step3. 判断线程池中的正在执行任务的线程数是否达到maximumPoolSize。
  • 如果没有达到,就创建一个线程来执行新的任务;
  • 如果达到了,就执行拒绝策略

 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线程池 面试考点相关推荐

  1. Java 线程池 8 大拒绝策略,面试必问!

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:KL博客 kailing.pub/article/index/arcid/255.h ...

  2. 面试必问---Java线程池8大拒绝策略

    前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...

  3. 面试官问你Java线程池--怎么样回答才能让面试官知道你真的懂了!

    一.引言 不管是Java面试还是Android面试,线程池都是面试官高频考察的点,那我们怎么回答,才能让面试官了解到我们是真的懂Java线程池了呢?这篇文章不涉及到线程池的使用和原理,如果你还不知道怎 ...

  4. Java面试系列之并发编程专题-Java线程池灵魂拷问

    金三银四跳槽季即将来临,想必有些猿友已经蠢蠢欲动在做相关的准备了!在接下来的日子里,笔者将坚持写作.分享Java工程师在面试求职期间的方方面面,包括简历制作.面试场景复现.面试题解答.谈薪技巧 以及 ...

  5. java线程池_Java 线程池 8 大拒绝策略,面试必问!

    点击上方 Java后端,选择设为星标 技术博文,及时送达 前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的 ...

  6. Java多线程系列(三):Java线程池的使用方式,及核心运行原理

    之前谈过多线程相关的4种常用Java线程锁的特点,性能比较.使用场景,今天主要分享线程池相关的内容,这些都是属于Java面试的必考点. 为什么需要线程池 java中为了提高并发度,可以使用多线程共同执 ...

  7. Java 线程池必知的8 大拒绝策略

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | kailing.pub/article/ind ...

  8. java线程池的使用例子,不愧是大佬

    京东Java研发岗一面(基础面,约1小时) 自我介绍,主要讲讲做了什么和擅长什么 springmvc和spring-boot区别 @Autowired的实现原理 Bean的默认作用范围是什么?其他的作 ...

  9. java线程池队列场景,Java面试题汇总

    01 并发宝典:面试专题 面试专题分为四个部分,分别如下 Synchronized 相关问题 可重入锁 ReentrantLock 及其他显式锁相关问题 Java 线程池相关问题 Java 内存模型相 ...

  10. Java线程池(Executor)详解和用法

    背景 面试的时候经常会被三连问.用过吗?如何用的?场景是什么?所以有必要好好的研究下线程池迫在眉睫. 1.讲解之前先了解下 retry: 因为源码中有这个retry标记 先看一个简单的例子 /*** ...

最新文章

  1. 扎克伯格AR野心:下个十年,远程「闪现」,不出家门跑到朋友家聊天
  2. 做一个略调皮的个人主页--相册与随笔篇
  3. stream的filter用法
  4. oracle元字符,正则表达式元字符
  5. Linux下scp命令的用法
  6. CentOS7.6下安装Ambari
  7. 【二分+二维前缀和】Largest Allowed Area
  8. 在一个热图中使用多个颜色主题
  9. linux脚本定时运行脚本,linux定时运行命令脚本——crontab
  10. 2018最有影响力的CRM系统排行榜
  11. linux系统调用使用方法,Linux系统的使用以及系统调用的开发方法OS.ppt
  12. dx 汇编dec_汇编语言算术指令
  13. 《东周列国志》第十九回 擒傅瑕厉公复国 杀子颓惠王反正
  14. Android工作日志
  15. php图片上传为base64,php实现base64图片上传方式实例代码
  16. 网络技术领域专业术语解释大全-170个术语
  17. 《点燃我,温暖你》李峋 代码 爱心❤ - 源代码
  18. 项目启动找不到资源文件可能的解决办法
  19. 秒杀刘海屏,有望实现手机|平板|电脑三合一,可折叠屏幕究竟是何方神圣?
  20. Java 手机号中间四位隐藏 MySQL函数手机号四位隐藏 Oracle手机号隐藏Java手机号码隐藏

热门文章

  1. Seaborn学习记录(1)
  2. Angular4+ 页面切换 显示进度条
  3. easyui missingMessage
  4. markdown的基本使用方法
  5. c# foreach循环二维数组
  6. python2.7.7笔记if in
  7. speex的基本编码和解码流程
  8. Youzi2D推出开源HTML5游戏加速引擎
  9. 一些面试题目(网易游戏2011.10.15校园招聘会笔试题)
  10. Django知识总结