线程池常问问题:
线程池各个参数的作用,简单阐述一下线程池工作流程。
常见的线程池有哪些,分别适用于什么场景?
使用无界队列的线程会导致内存飙升吗?
线程池的好处
- 降低线程创建和销毁线程造成的开销
- 提高响应速度。任务到达时,相对于手工创建一个线程,直接从线程池中拿线程,速度肯定快很多
- 提高线程可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以进行统一分配、调优和监控
线程池的核心参数
无论是创建何种类型线程池(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:主线程中执行任务
线程池的执行流程
当提交一个新任务,线程池的处理流程如下:
- 判断线程池中核心线程数是否已达到核心线程数corePoolSize,若否,则创建一个新核心线程执行任务;
- 若核心线程数已达到核心线程数corePoolSize,判断阻塞队列workQueue是否已满,若未满,则将新任务添加进阻塞队列
- 若阻塞队列已满,再判断,线程池中线程数是否达到最大线程数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。
面试需要掌握那些技能?
1. Java基础知识:包括面向对象编程、集合框架、多线程编程、JVM、测试和调试技术等。
2. 熟悉Spring框架:包括Spring MVC、Spring Boot、Spring Cloud等。
3. 掌握常见的数据库操作技术:如SQL语句、关系型数据库和非关系型数据库等。
4. 熟练使用版本控制工具:如Git等。
5. 对Web开发有一定的了解,熟悉前端相关技术:如HTML、CSS、JavaScript等。
6. 能够写高效的算法,并对数据结构有一定的了解。
7. 有良好的代码习惯,能够编写易于维护和扩展的代码,并理解单元测试和集成测试等概念。
8. 在面试过程中,还需要表达清晰、思路清晰明了、能够准确地回答面试官提出的问题,此外,自信、积极和礼貌也是很重要的。
2023年大厂面试官常问的技术核心知识点
1. Java基础知识:Java语言的基本知识,包括数据类型、继承、多态、接口等。
2. 面向对象编程:对面向对象编程原则和设计模式的理解,如单例、工厂、观察者、策略等。
3. 数据库知识:对关系型数据库和非关系型数据库操作的熟悉程度,掌握SQL语言,了解事务管理机制,并清楚地描述ORM框架的使用场景及实际操作。
4. Web开发:Web开发相关技术,例如Servlet、JSP、Spring MVC、JSON、RESTful API等。熟悉HTTP/HTTPS协议以及网络通信机制。
5. 常用框架:Spring、Hibernate、MyBatis等框架,尤其是Spring框架,深入理解Spring IOC,AOP等核心原理,知道如何配置基础设施组件,如事务管理、缓存等基础组件。
6. 分布式系统架构:分布式系统相关技术,如Dubbo、Zookeeper等,对微服务架构模式有一定的了解,熟悉分布式锁、分布式缓存、分布式数据存储等高可用性方案。
7. 性能排查:了解性能优化的方法,包括代码和SQL调优等,并且熟悉性能监测和分析工具,例如掌握JVM内存结构及堆栈排查技术。
8. 算法和数据结构:有基本的算法和数据结构知识,例如排序、查找、哈希表等。
我最近整理了一些小伙伴们发给我的面试题以及我的一些最新的面试等学习资料,有需要的小伙伴可以找我领取下。或者点击 → 《2023最新Java后端全套VIP面试学习资源》直接获取以下Java后端架构VIP进阶学习面试资料。
资料里面包含了:Java基础、MySQL、jvm、分布式、性能优化、spring 、spring boot、spring cloud、 MyBatis、Netty源码分析、算法、乙级高并发、Redis、dubbo、Tomcat、集合框架、锁、MQ、百万简历模板等等学习视频资料。
资料如图展示:(知识其中一部分)
同时也欢迎大家关注公众号【Java烂猪皮】,回复【666】,获取最新Java后端架构VIP学习资料以及视频学习教程,然后一起学习,一文在手,面试我有。
公众号【Java烂猪皮】里面每天都会分享很多独家的干货内容,比如:Java后端学习路线,分享实战项目,源码分析,百万级系统设计,系统上线的一些坑,MQ专题,真实面试题,每天都会回答大家提出的问题。
每一个专栏都是大家非常关心,和非常有价值的话题,我相信在专栏中你会学到很多东西,一起共勉。