1.线程池参数

多线程 - 【必考】线程池的常用参数_创建线程

 

 

2.线程池执行流程

2.1 流程图

多线程 - 【必考】线程池的常用参数_守护线程_02

 

 

2.2 线程创建的流程

当任务提交之后,线程池首先会检查当前线程数,如果当前的线程数小于核心线程数(corePoolSize),比如最开始创建的时候线程数为 0,则新建线程并执行任务。

当提交的任务不断增加,创建的线程数等于核心线程数(corePoolSize),新增的任务会被添加到 workQueue 任务队列中,等待核心线程执行完当前任务后,重新从 workQueue 中获取任务执行。

假设任务非常多,达到了 workQueue 的最大容量,但是当前线程数小于最大线程数(maximumPoolSize),线程池会在核心线程数(corePoolSize)的基础上继续创建线程来执行任务。

假设任务继续增加,线程池的线程数达到最大线程数(maximumPoolSize),如果任务继续增加,这个时候线程池就会采用拒绝策略来拒绝这些任务。

2.3 小结

在任务不断增加的过程中,线程池会逐一判断

核心线程数(corePoolSize)

任务队列(workQueue)

最大线程数(maximumPoolSize)

拒绝策略

3.核心线程数和最大线程数

corePoolSize 是核心线程数,初始大小是 0,但是在创建线程之后,核心线程会常驻在线程池中,即使没有任务执行,也不会被销毁。随着任务数的增加,当任务队列(workQueue )满了之后,线程池根据最大线程数(maximumPoolSize)来创建非核心线程,当任务执行完,线程有空闲,非核心线程会被回收。

“正式员工” 与 “外包员工”

一般大型银行会有很多项目要做,但是银行的正式编制有限,这种时候就需要采用“人力外包”的形式。corePoolSize 相当于正式员工,而 (maximumPoolSize - corePoolSize) 相当于外包员工,当项目比较少的时候,正式员工就可以处理,但是项目增多时超过了处理负荷,就需要增加外包人员协助进行处理。

当项目完成或者结束之后,正式员工还是在银行上班,等待任务或者处理新的任务,而外包人员则会结束和银行的合同。

4.keepAliveTime+时间单位

第三个参数是 keepAliveTime + 时间单位,当线程池中线程数量多于核心线程数时,而此时又没有任务可做,线程池就会检测线程的 keepAliveTime,如果超过规定的时间,无事可做的线程就会被销毁,以便减少内存的占用和资源消耗。如果后期任务又多了起来,线程池也会根据规则重新创建线程,所以这是一个可伸缩的过程,比较灵活,我们也可以用 setKeepAliveTime 方法动态改变 keepAliveTime 的参数值。


5.ThreadFactory



ThreadFactory 使用的是抽象工厂模式


第四个参数是 ThreadFactory,ThreadFactory 实际上是一个线程工厂,它的作用是生产线程以便执行任务。我们可以选择使用默认的线程工厂,创建的线程都会在同一个线程组,并拥有一样的优先级,且都不是守护线程,我们也可以选择自己定制线程工厂,以方便给线程自定义命名,不同的线程池内的线程通常会根据具体业务来定制不同的线程名。

为什么创建的线程不是守护线程?



守护线程:和主线程一起结束的线程,叫守护线程。
非守护线程:主线程的结束不影响线程的执行的线程,也叫用户线程。


源码如下:



public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())// 判断是否是守护线程
t.setDaemon(false);// 如果是则设置为 false
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);// 设置优先级为 5
return t;
}


有源码可知,如果线程是守护线程,会重新设置为非守护线程,而设置为非守护线程的原因是保证该线程不受主线程的影响。

 

6.workQueue 阻塞队列

阻塞队列,后续专题章节进行讲解:​​线程池常用的阻塞队列有哪些​

7.Handler 拒绝策略

拒绝策略,后续专题章节进行讲解:​​线程池的4种拒绝策略​