Java后端高频面试问题:线程池

1.什么是线程池?

线程池:事先创建若干空闲的线程放入一个池中(容器),当一个任务提交到线程池时,线程池就会启动一个空闲的线程去处理任务,当任务结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。

2.使用线程池的好处?

①降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

②提高响应速度:当任务到达时,可以不需要等待线程创建就能立即执行。

③提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,监控和调优。

3.线程池的工作流程?

①判断核心线程数是否已满,如果没满,及时现在有空闲线程,也创建一个新的工作线程来执行任务

②如果核心线程数已满,再判断任务队列是否已满,如果没满则将新提交的任务添加在工作队列中。

③如果任务队列已满,则判断最大线程数是否已满,如果没满则创建一个新的工作线程来执行任务,如果最大线程数已满,则执行拒绝策略。


4.怎么创建一个线程池?

1.通过ThreadPoolExecutor构造方法,通过传递参数的方式创建。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
        null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

2.通过Executors工具类创建。

Java 5新增了一个Executors工厂类来产生线程池,该工厂类包含

如下几个静态工厂方法来创建线程池。创建出来的线程池,都是通过ThreadPoolExecutor类来实现的。


5.重复创建线程为什么会开销过大?

Java线程的创建成本很高,因为需要进行大量的工作:

1.必须为线程堆栈分配和初始化大量内存块。

2.需要进行系统调用,以便在主机OS中创建/注册本机线程。

3.描述符需要创建、初始化并添加到JVM内部数据结构中。


6.线程池的种类?

newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程

将会被缓存在线程池中。

newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数的线程池。

newSingleThreadExecutor():创建一个只有单线程的线程池,它相当于调用newFixedThread

Pool()方法时传入参数为1。

newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池,它可以在指定延

迟后执行线程任务。corePoolSize指池中所保存的线程数,即使线程是空闲的也被保存在线程池

内。

newSingleThreadScheduledExecutor():创建只有一个线程的线程池,它可以在指定延迟后执行

线程任务。

ExecutorService newWorkStealingPool(int parallelism):创建持有足够的线程的线程池来支持

给定的并行级别,该方法还会使用多个队列来减少竞争。

ExecutorService newWorkStealingPool():该方法是前一个方法的简化版本。如果当前机器有4个

CPU,则目标并行级别被设置为4,也就是相当于为前一个方法传入4作为参数。


7.线程池有哪些状态?

①Running:能接受新提交的任务,能处理阻塞队列中的任务。

②Shutdown:不接受新提交的任务,可以处理阻塞队列中已有的任务。

③Stop:不接受新任务,也不处理队列中的任务,中断正在处理任务的线程。

④Tiding:所有任务都执行完(包含阻塞队列里面的任务),当前线程池活动线程数workerCount为0,

线程池进入该状态后会调用terminate()方法进入Terminated状态。

⑤Terminated:在terminate()方法执行完后进入该状态。


8.线程池有哪些参数?每个参数的作用是什么?

corePoolSize(核心工作线程数):当向线程池提交一个任务时,若线程池已创建的线程数小于

corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线

程数大于或等于corePoolSize时。

②maximumPoolSize(最大线程数):线程池所允许的最大线程个数。当队列满了,且已创建的线

程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。另外,对于无界队列,可忽

略该参数。

③keepAliveTime(多余线程存活时间):当线程池中线程数大于核心线程数时,线程的空闲时间如

果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数。

TimeUnit(时间单位):keepAliveTime的时间单位。

workQueue(队列):用于传输和保存等待执行任务的阻塞队列。

threadFactory(线程创建工厂):用于创建新线程。threadFactory创建的线程也是采用newThread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)。

handler(拒绝策略):当线程池和队列都满了,再加入线程会执行此策略。



9.线程池的拒绝策略?

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就

会采取任务拒绝策略,通常有以下四种策略:

1. AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

2. DiscardPolicy:也是丢弃任务,但是不抛出异常。

3. DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复该过程)。

4. CallerRunsPolicy:由调用线程处理该任务。

线程池的默认拒绝策略为 AbortPolicy。


10.线程池的阻塞队列?

阻塞队列

①第一种阻塞队列是 LinkedBlockingQueue。对应的线程池:newSingleThreadExecutor( )和newFixedThreadPool(int n)

LinkedBlockingQueue,它的容量是 Integer.MAX_VALUE,为 231 -1 ,是一个非常大的值,可以认为是无界队列。

FixedThreadPool 和 SingleThreadExecutor 线程池的线程数是固定的,所以没有办法增加特别多的线程来处理任务,这时就需要 LinkedBlockingQueue 这样一个没有容量限制的阻塞队列来存放任务。


②第二种阻塞队列是 SynchronousQueue。对应的线程池是 newCachedThreadPool( )

线程池 CachedThreadPool 的最大线程数是 Integer.MAX_VALUE,可以理解为线程数是可以无限扩展的。

CachedThreadPool 和上一种线程池 FixedThreadPool 的情况恰恰相反,FixedThreadPool 的情况是阻塞队列的容量是无限的,而这里 CachedThreadPool 是线程数可以无限扩展,所以 CachedThreadPool 线程池并不需要一个任务队列来存储任务,因为一旦有任务被提交就直接转发给线程或者创建新线程来执行,而不需要另外保存它们。

我们自己创建使用 SynchronousQueue 的线程池时,如果不希望任务被拒绝,那么就需要注意设置最大线程数要尽可能大一些,以免发生任务数大于最大线程数时,没办法把任务放到队列中也没有足够线程来执行任务的情况。


③第三种阻塞队列是DelayedWorkQueue。对应的线程池分别是 newScheduledThreadPool (int n)和newSingleThreadScheduledExecutor( )

这两种线程池的最大特点就是可以延迟执行任务,比如说一定时间后执行任务或是每隔一定的时间执行一次任务。

DelayedWorkQueue 的特点是内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序,内部采用的是“堆”的数据结构(堆的应用之一就是 优先级队列)。之所以线程池 ScheduledThreadPool 和 SingleThreadScheduledExecutor 选择 DelayedWorkQueue,是因为它们本身正是基于时间执行任务的,而延迟队列正好可以把任务按时间进行排序,方便任务的执行。






#高频知识点汇总##Java##学习路径#
全部评论
Java后端面试高频问题:HashMap的底层原理:https://www.nowcoder.com/discuss/820700 Java后端面试高频问题:ConcurrentHashMap:https://www.nowcoder.com/discuss/820701 Java后端面试高频问题:BIO、NIO、AIO的区别:https://www.nowcoder.com/discuss/820703 Java后端高频面试问题:线程池:https://www.nowcoder.com/discuss/820704 Java后端高频面试问题:AQS和CAS:https://www.nowcoder.com/discuss/820706 Java后端高频面试问题:String相关:https://www.nowcoder.com/discuss/821375 Java后端高频面试问题:ArrayList相关:https://www.nowcoder.com/discuss/821377 Java后端高频面试问题:垃圾回收机制:https://www.nowcoder.com/discuss/822354 Java后端高频面试问题:MySQL索引和事务:https://www.nowcoder.com/discuss/823047
1 回复 分享
发布于 2021-12-18 15:33
2022届秋招Java后端企业面试真题汇总①:https://www.nowcoder.com/discuss/817566 2022届秋招Java后端企业面试真题汇总②:https://www.nowcoder.com/discuss/818250 2022届秋招Java后端企业面试真题汇总③:https://www.nowcoder.com/discuss/818255
点赞 回复 分享
发布于 2021-12-13 10:23
2022届秋招Java后端高频知识点汇总①--Java基础: https://www.nowcoder.com/discuss/819297 2022届秋招Java后端高频知识点汇总②--Java集合: https://www.nowcoder.com/discuss/819300 2022届秋招Java后端高频知识点汇总③--多线程: https://www.nowcoder.com/discuss/819302 2022届秋招Java后端高频知识点汇总④--Java中的锁: https://www.nowcoder.com/discuss/819304 2022届秋招Java后端高频知识点汇总⑤--JVM: https://www.nowcoder.com/discuss/819307 2022届秋招Java后端高频知识点汇总⑥--MySQL: https://www.nowcoder.com/discuss/819308 2022届秋招Java后端高频知识点汇总⑦--Redis: https://www.nowcoder.com/discuss/819310 2022届秋招Java后端高频知识点汇总⑧--计算机网络: https://www.nowcoder.com/discuss/819312 2022届秋招Java后端高频知识点汇总⑨--操作系统: https://www.nowcoder.com/discuss/819316 2022届秋招Java后端高频知识点汇总⑩--Spring: https://www.nowcoder.com/discuss/819319
点赞 回复 分享
发布于 2021-12-13 10:23
需要Java面试资料的私信我
点赞 回复 分享
发布于 2021-12-13 10:24
🎉恭喜牛友成功参与 【创作激励计划】高频知识点汇总专场,并通过审核! ------------------- 创作激励计划5大主题专场等你来写,最高可领取500元京东卡和500元实物奖品! 👉快来参加吧:https://www.nowcoder.com/discuss/804743
点赞 回复 分享
发布于 2021-12-13 10:55
666
点赞 回复 分享
发布于 2021-12-13 20:25

相关推荐

和蔼:在竞争中脱颖而出,厉害! 但是有一个小问题:谁问你了?😡我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了
点赞 评论 收藏
分享
7 68 评论
分享
牛客网
牛客企业服务