【260期】Java线程池,这篇能让你和面试官聊了半小时

发布时间:2022-06-28 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了【260期】Java线程池,这篇能让你和面试官聊了半小时脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

线程池常问问题:

  • 线程池各个参数的作用,简单阐述一下线程池工作流程。
  • 常见的线程池有哪些,分别适用于什么场景?
  • 使用无界队列的线程会导致内存飙升吗?

线程池的好处

  1. 降低线程创建和销毁线程造成的开销
  2. 提高响应速度。任务到达时,相对于手工创建一个线程,直接从线程池中拿线程,速度肯定快很多
  3. 提高线程可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以进行统一分配、调优和监控

线程池的核心参数

无论是创建何种类型线程池(FixedThreadPool、CachedThreadPool…),均会调用ThreadPoolExecutor构造函数。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
}
  • corePoolSize:核心线程最大数量,通俗点来讲就是,线程池中常驻线程的最大数量
  • maximumPoolSize:线程池中运行最大线程数(包括核心线程和非核心线程)
  • keepAliveTime:线程池中空闲线程(仅适用于非核心线程)所能存活的最长时间
  • unit:存活时间单位,与keepAliveTime搭配使用
  • workQueue:存放任务的阻塞队列
  • handler:线程池饱和策略

几种典型的工作队列:

  • ArrayBlockingQueue:使用数组实现的有界阻塞队列,必须设定容量,先进先出
  • LinkedBlockingQueue:使用链表实现的阻塞队列,先进先出,可以设置其容量,默认为Interger.MAX_VALUE
  • ConcurrentLinkedQueue:基于链表实现的无界非阻塞队列。此队列按照 FIFO(先进先出)原则对元素进行排序。此队列不允许使用 null 元素。
  • PriorityBlockingQueue:使用平衡二叉树堆,实现的具有优先级的无界阻塞队列
  • DelayQueue:无界阻塞延迟队列,队列中每个元素均有过期时间,当从队列获取元素时,只有过期元素才会出队列。队列头元素是最块要过期的元素。
  • SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作,必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态

线程池饱和策略分为以下几种:

  • AbortPolicy:直接抛出一个异常,默认策略
  • DiscardPolicy:直接丢弃任务
  • DiscardOldestPolicy:抛弃下一个将要被执行的任务(最旧任务)
  • CallerRunsPolicy:主线程中执行任务

线程池的执行流程

当提交一个新任务,线程池的处理流程如下:

  1. 判断线程池中核心线程数是否已达到核心线程数corePoolSize,若否,则创建一个新核心线程执行任务;
  2. 若核心线程数已达到核心线程数corePoolSize,判断阻塞队列workQueue是否已满,若未满,则将新任务添加进阻塞队列
  3. 若阻塞队列已满,再判断,线程池中线程数是否达到最大线程数maximumPoolSize,若否,则新建一个非核心线程执行任务。若已达到,则执行线程池饱和策略。

几种常用的线程池

SingleThreadExecutor

创建单个线程。它适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。

SingleThreadExecutor的corePoolSize和maximumPoolSize被设置为1,使用无界队列LinkedBlockingQueue作为线程池的工作队列。

使用场景:串行执行任务

FixedThreadPool

一种线程数量固定的线程池。

corePoolSize等于maximumPoolSize,所以线程池中只有核心线程,使用无界阻塞队列LinkedBlockingQueue作为工作队列

使用场景:适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。

CachedThreadPool

核心线程数为0,线程最大数为Integer.MAX_VALUE,即可以创建无限的非核心线程。使用SynchronousQueue作为线程池的阻塞队列。

使用场景:执行大量短生命周期任务。因为maximumPoolSize是无界的,每次提交任务,都会立即有线程去处理,因此CachedThreadPool适用于处理大量、耗时少的任务。

ScheduledThreadPool

指定核心线程数,线程最大数为Integer.MAX_VALUE,非核心线程存活时间为0,工作队列使用DelayedWorkQueue,所以线程池仅仅包含固定数目的核心线程。

使用场景:周期性执行任务,并且需要限制线程数量的场景

使用无界队列的线程池会导致内存飙升吗?

答案 :会的,newFixedThreadPool使用了无界的阻塞队列LinkedBlockingQueue,如果线程获取一个任务后,任务的执行时间比较长,会导致队列的任务越积越多,导致机器内存使用不停飙升, 最终导致OOM。

 

吃水不忘挖井人:

  • 【260期】Java线程池,这篇能让你和面试官聊了半小时

 

脚本宝典总结

以上是脚本宝典为你收集整理的【260期】Java线程池,这篇能让你和面试官聊了半小时全部内容,希望文章能够帮你解决【260期】Java线程池,这篇能让你和面试官聊了半小时所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: