目录

  • What?
  • Why?
  • 分类?
    • 1. newCachedThreadPool
      • 1.1.what?
      • 1.2 代码实例
      • 1.3 执行结果
      • 1.4 源码分析
      • 1.5 缺点
    • 2.newFixedThreadPool
      • 2.1 What?
      • 2.2 代码实例
      • 2.3 结果
      • 2.4 源码分析
      • 2.5 缺点
    • 3. newScheduledThreadPool
      • 3.1 what
      • 3.2 代码示例
      • 3.3 执行结果
      • 3.4 源码分析
      • 3.5 缺点
    • 4、newSingleThreadExecutor
      • 4.1 what?
      • 4.2 代码示例
      • 4.3 运行结果
      • 4.4 源码分析
      • 4.5 缺点
  • 线程池
    • 1.线程池原理
    • 2. 自定义线程池
    • 3、 拒绝策略
    • 4. 合理配置线程池
    • 5.应用
  • 总结

 近期听到了很多求职小伙伴的心声,线程池不是很了解,而且只知道如果运用,更别提深层研究了,导致每次都被面试官问的哑口无言。那我就做回天使吧,给大家系统一下。
 我的套路是从原理----应用----源码;让你彻底弄成线程池。

What?

  线程池,就是一个池子嘛,但是这个池子不是装水的,而是装线程的;
  想想我们平常水池的是啥,还不是为了用水的时候方便,节省了来回运水的时间;而且我们可以让水可以循环利用,水资源多么宝贵呀,节约了水资源;同理,当面试官再问你,线程池好处的时候,是不是就可以结合“水池作用”,跟面试官装一把了;

Why?

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  2. **提高响应速度。**当任务到达时,任务可以不需要等到线程创建就能立即执行。
  3. **提高线程的可管理性。**线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

分类?

  多线程是采用了Executor框架。具体的类图关系如下;ThreadPoolExecutor是线程池创建的核心类。然后线程池的具体创建方式如下几种:

1. newCachedThreadPool

1.1.what?

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

1.2 代码实例

public class CacheThread  {public static void main(String[] args) {ExecutorService cachThread= Executors.newCachedThreadPool();for (int i = 0; i <10 ; i++) {final int temp=i;cachThread.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"当前线程的==="+temp);}});}}

1.3 执行结果


由上图,我们也得出了结果:虽然线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

1.4 源码分析

1.5 缺点

 最大线程数为Integer.MAX_VALUE,可能会创建很多的线程,然后导致OOM异常;

2.newFixedThreadPool

2.1 What?

 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

2.2 代码实例

public class FixThread {public static void main(String[] args) {// 有5个线程ExecutorService fixThread= Executors.newFixedThreadPool(5);for (int i = 0; i <10 ; i++) {final  int temp=i;fixThread.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"当前线程=="+temp);}});}}
}

2.3 结果


我们可以得出结论:因为线程池的大小是5,所以它的好处是可以循环利用线程,合理的分配资源,去执行任务;

2.4 源码分析


 通过源码,可以看出,它是核心线程数和最大线程数是相同的,采用的是LinkedBlockQueue<>队列;

2.5 缺点

LinkedBlockQueue<>没有设定范围,它的值为Inter.Max_Value,这样类似于无界队列,然后会存储很多的线程,造成OOM异常;

3. newScheduledThreadPool

3.1 what

 创建一个定长线程池,支持定时及周期性任务执行

3.2 代码示例

    public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService= Executors.newScheduledThreadPool(5);for (int i = 0; i < 10; i++) {final  int temp=i;scheduledExecutorService.schedule(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"当前线程"+temp);}},4, TimeUnit.SECONDS);}}
}

3.3 执行结果

延迟4秒执行,运算出下面结果

3.4 源码分析


通过源码分析,它底层也是 调用的ThreadPoolExecutor。

3.5 缺点

  同newCachedThreadPool一样,最大线程数为Integer.MAX_VALUE,可能会创建很多的线程,然后导致OOM异常;

4、newSingleThreadExecutor

4.1 what?

 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

4.2 代码示例

public class SingleThread  {public static void main(String[] args) {ExecutorService singleThread= Executors.newSingleThreadExecutor();for (int i = 0; i <10 ; i++) {final  int temp=i;singleThread.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"当前线程"+temp);}});}}
}

4.3 运行结果

 只有一个线程在执行;

4.4 源码分析

4.5 缺点

同newFixThreadPool一样,LinkedBlockQueue<>没有设定范围,它的值为Inter.Max_Value,这样类似于无界队列,然后会存储很多的线程,造成OOM异常;

线程池

 由上面的几中线程的创建方式,我们可以看出,他们底层都调用了 “ThreadPoolExecutor”,上面的方法都有弊端,所以我们可以用ThreadPoolExecutor然后自定义线程池,根据我们项目中的需要;

1.线程池原理

  1. 判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
  2. 线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
  3. 判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

2. 自定义线程池

【案例一】此时运行5个任务===最大线程数+队列数

public class ThreadPoolExcutor {public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor= new ThreadPoolExecutor(1,2,60L,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),new ThreadPoolExecutor.AbortPolicy());//此时运行5个任务,没有超过  最大线程数+队列数for (int i = 1; i <=5 ; i++) {final  int temp=i;taskThread t1=new taskThread("任务线程");threadPoolExecutor.execute(t1);}}
}
class  taskThread implements Runnable{private  String taskName;public  taskThread(String taskName){this.taskName=taskName;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"当前现成的任务"+taskName);}
}

运行的结果:

【案例二】:此时用了两个线程,进行了复用,但是我们如果尝试一下运行6个任务(超过了最大线程数+队列的数据);
运行结果:

由结果可知,我们也就更进一步的明白了线程池的运行原理,当我们执行的任务超过了 最大线程数+队列中的线程,然后线程池就会采用一些拒绝策略,进行拒绝;

3、 拒绝策略

  1. AbortPolicy(默认):直接抛出RejectedException异常,阻止系统正常运行;
  2. CallerRunsPolicy:不会抛弃任务也不会抛出异常,而是回退给调用者;
  3. DiscardOldestPolicy:丢弃等待最久的任务,然后把当前任务加入队列中;
  4. DiscardPolicy:直接丢弃任务,不做任何处理。

上面的例子中,我采用的是默认AbortPolicy的拒绝策略,然后直接抛异常,下面我演示一下用 “CallerRunsPolicy”进行调用,查看一下结果;

4. 合理配置线程池

 我们在项目中使用线程池需要自定义最大线程数,那我们可以根据以下两点进行判断;

1 . IO密集型: 即该任务需要大量的IO,即大量的阻塞。在单线程上运行IO密集型的任务会导致浪费大量的;
这时候我们可以设定:最大线程数=CPU核数 * 2;
2 CPU密集型:该任务需要大量的运算,而没有阻塞,CPU一直全速运行。
这时候我们可以设定:最大线程数=CPU核数 ;

5.应用

 在项目中我们需要多个任务的处理的时候,比如 使用多线程去消费mq中的数据等等;

总结

 在跟面试官吹的时候,可以借鉴上面的思虑然后在加上在项目中的经验,调理清晰;让面试官也大开眼界,不选你,选谁!

跟面试官谈【线程池】相关推荐

  1. 面试官系统精讲Java源码及大厂真题 - 40 打动面试官:线程池流程编排中的运用实战

    40 打动面试官:线程池流程编排中的运用实战 没有智慧的头脑,就像没有蜡烛的灯笼. --托尔斯泰 引导语 在线程池的面试中,面试官除了喜欢问 ThreadPoolExecutor 的底层源码外,还喜欢 ...

  2. 面试官一个线程池问题把我问懵逼了。

    你好呀,我是why哥. 前几天,有个朋友在微信上找我.他问:why哥,在吗? 我说:发生肾么事了? 他啪的一下就提了一个问题啊,很快. 我大意了,随意瞅了一眼,这题不是很简单吗? 结果没想到里面还隐藏 ...

  3. main线程 子线程 顺序_面试官:线程池如何按照core、max、queue的执行顺序去执行?详解...

    前言 这是一个真实的面试题. 前几天一个朋友在群里分享了他刚刚面试候选者时问的问题:"线程池如何按照core.max.queue的执行循序去执行?". 我们都知道线程池中代码执行顺 ...

  4. adguard没有核心 core no_面试官:线程池如何按照core、max、queue的执行顺序去执行?...

    前言 这是一个真实的面试题. 前几天一个朋友在群里分享了他刚刚面试候选者时问的问题:"线程池如何按照core.max.queue的执行循序去执行?". 我们都知道线程池中代码执行顺 ...

  5. 腾讯面试题:创建索引时,你会怎么考虑呢?(看完你就能和面试官谈人生了)

    title: 腾讯面试题:创建索引时,你会怎么考虑呢?(看完你就能和面试官谈人生了) tags: 面试常见题 腾讯面试题:创建索引时,你会怎么考虑呢?(看完你就能和面试官谈人生了) 腾讯面试题:创建索 ...

  6. 浅谈线程池(下):相关试验及注意事项

    三个月,整整三个月了,我忽然发现我还有三个月前的一个小系列的文章没有结束,我还欠一个试验!线程池是.NET中的重要组件,几乎所有的异步功能依赖于线程池.之前我们讨论了线程池的作用.独立线程池的存在意义 ...

  7. 浅谈线程池(中):独立线程池的作用及IO线程池

    在上一篇文章中,我们简单讨论了线程池的作用,以及CLR线程池的一些特性.不过关于线程池的基本概念还没有结束,这次我们再来补充一些必要的信息,有助于我们在程序中选择合适的使用方式. 独立线程池 上次我们 ...

  8. 浅谈线程池(上):线程池的作用及CLR线程池

    线程池是一个重要的概念.不过我发现,关于这个话题的讨论似乎还缺少了点什么.作为资料的补充,以及今后文章所需要的引用,我在这里再完整而又简单地谈一下有关线程池,还有.NET中各种线程池的基础.更详细的内 ...

  9. Hystrix面试 - 深入 Hystrix 线程池隔离与接口限流

    Hystrix面试 - 深入 Hystrix 线程池隔离与接口限流 前面讲了 Hystrix 的 request cache 请求缓存.fallback 优雅降级.circuit breaker 断路 ...

  10. Hystrix面试 - 基于 Hystrix 线程池技术实现资源隔离

    Hystrix面试 - 基于 Hystrix 线程池技术实现资源隔离 上一讲提到,如果从 Nginx 开始,缓存都失效了,Nginx 会直接通过缓存服务调用商品服务获取最新商品数据(我们基于电商项目做 ...

最新文章

  1. Eclipse开发环境设置
  2. 美术干货:用Blender绘制low poly风格的游戏角色
  3. c++中声明和定义的区别(这个兄弟写的解决了我的疑惑)
  4. 原生js打印指定节点元素
  5. 西餐美食店响应式网站模板
  6. 互联网医生-ICMP协议
  7. 【南邮操作系统实验】页面置换算法 (FIFO、LRU、OPT)Java 版
  8. linux下limits.conf 修改不生效的原因
  9. kindle3 破解字体
  10. linux识别罗兰声卡,罗兰系列声卡直播K歌模式调试方法
  11. 51单片机下的温控智能小风扇
  12. R语言ggplot2可视化哑铃图、强调从一个点到另一个点的变化、数量的变化、客户满意度的变化等(Dumbbell Plot)、为可视化图像添加标题、题注信息
  13. Bytom BIP-32协议和BIP-44协议
  14. 2008年IT产业38个判断(转载)
  15. @ComponentScan注解
  16. 实验题目:约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,m为任意一个正整数。从第一个人开始顺时针方向自1起顺序报数,报到m时停止并且报m的人出列,再从他的下一个人
  17. 增量式旋转编码器的使用,以arduino为例
  18. 将字符串,数组等任意格式转为json(JSON)数据,Arrays是数组工具类,将任意数组转字符串或数组操作
  19. navigationController中navigationBar 的设置
  20. AAA服务器原理,路由交换学习笔记(十七)AAA基本原理

热门文章

  1. LoRaWAN介绍10 定位
  2. java8 list 转Map的各种写法
  3. function函数的各种写法
  4. [第3课] 象形统计图
  5. 第八章 我国农村商品流通
  6. BQ40Z80 CHG DSG打不开
  7. linux支持xfs文件系统,LINUX下使用XFS文件系统
  8. 散列表、LinkedHashMap源码分析
  9. Python math.cosh() 方法
  10. 【Web前端HTML5CSS3】——CSS语法与选择器(超级全面)