徐无忌并发编程笔记:线程池的核心参数都是干什么的?平时应该如何使用?

完成:第一遍

1.为什么说线程是重量级对象?

创建与销毁一个线程并不像创建一个对象那么简单,
需要调用操作系统内核的 API
整个过程是一个偏重且耗时的操作

并发的线程数量很多,且执行时间很多的任务就结束
频繁的创建与销毁会大大降低系统效率

需要一种办法可以对线程进行重复利用,完成任务后并不被销毁,可以继续执行其他任务

2.线程池的设计思路是什么?

线程池是一种线程的使用模式
它为了降低线程使用过程中
频繁的创建和销毁所带来的资源消耗与代价

提前创建一定数量的线程,他们时刻准备着
在新任务到达后就开始执行
在完成任务后,再重新回来继续待命

线程池负责对线程统一分配、调优与监控

3.使用线程池的优点有哪些?

相比于来一个任务创建一个线程的方式
使用线程池的优势体现在如下几点:

优点一:避免了线程的重复创建与开销带来的资源消耗代价

优点二:提升了任务响应速度,任务到达时,直接选一个线程执行而无需等待线程的创建

优点三:提高线程的可管理性,线程的统一分配和管理,也方便统一的监控和调优

3.线程池的工作原理是怎样的?

在线程池的内部,我们维护了一个阻塞队列 workQueue 和一组工作线程
工作线程的个数可以在初始化线程池的时候来指定

用户提交Runnable任务给线程池,任务会被加入到 workQueue 中

线程池内部维护的工作线程会消费 workQueue 中的任务并进行执行

4.如何使用Java中的线程池?

Java 提供的线程池相关的工具类中,最核心的是ThreadPoolExecutor

ThreadPoolExecutor的构造需要七大核心参数,定义了线程池的使用功能,参数设置很重要

5.线程池有哪七大核心参数?

ThreadPoolExecutor(
int corePoolSize
int maximumPoolSize
long keepAliveTime
TimeUnit unit
BlockingQueue workQueue
ThreadFactory threadFactory
RejectedExecutionHandler handler
)

6.什么是corePoolSize即核心线程数?

corePoolSize表示线程池保有的核心的线程数(最小的线程数)
核心线程会一直存活,即使这些线程处于空闲状态没有任务执行,他们也不会被销毁

把线程池类比为一个施工队,而线程就是施工队的工人

有些时候很闲项目比较少,但是施工队也不能把工人都遣散,至少要留 corePoolSize 个人坚守阵地

7.什么是maximumPoolSize 即线程池最大线程数量?

当项目比较多的时候,施工队就需要增加工人,但是也不能无限制地加

最多就加到 maximumPoolSize 个人,当闲下来的时候,施工队就要遣散工人,但是至少保留 corePoolSize 个人

8.如何通过keepAliveTime 和 unit 定义线程池忙和闲呢?

很简单,当线程池内部的线程数已经大于corePoolSize的时候,一个线程如果在一段时间内,都没有执行任务,说明很闲

keepAliveTime 和 unit 就是用来定义这个“一段时间”的参数。也就是说,如果一个线程空闲了keepAliveTime & unit这么久,那么这个空闲的线程就要被回收了

9.什么是workQueue即工作队列?

新任务被提交到线程池,优先使用核心线程进行执行,核心线程没有空闲的情况下,任务会进入到此工作队列中,任务调度时再从队列中取出任务

10.什么是ThreadFactory即线程工厂 ?

创建一个新线程时使用的工厂, 通过这个工厂可以自定义如何创建线程,例如可以给线程指定一个有意义的名字

11.什么是handler 即拒绝策略?

如果线程池中所有的线程(最大线程数)都在忙碌,并且工作队列也满了(前提是工作队列是有界队列),那么此时提交任务,线程池就会拒绝接收

至于拒绝的策略,可以通过 handler 这个参数来指定:

拒绝策略一:CallerRunsPolicy:提交任务的线程自己去执行该任务。

拒绝策略二:AbortPolicy:默认的拒绝策略,直接丢弃任务,抛出RejectedExecutionException。

拒绝策略三:DiscardPolicy:直接丢弃任务,没有任何异常抛出。

拒绝策略四:DiscardOldestPolicy:丢弃最老的任务,其实就是把最早进入工作队列的任务丢弃,然后把新任务加入到工作队列。

12.使用线程池要注意什么?

默认的拒绝策略要慎重使用。如果线程池处理的任务非常重要,建议自定义自己的拒绝策略;并且在实际工作中,自定义的拒绝策略往往和降级策略配合使用。

使用线程池,需要注意异常处理的问题。任务在执行的过程中出现运行时异常,会导致执行任务的线程终止,最稳妥和简单的方案还是捕获所有异常并按需处理。