Java 线程池的各个参数的含义

Java 线程池的各个参数的含义

1.线程池参数

参数名 含义
corePoolSize 核心线程数
maximumPoolSize 最大线程数
keepAliveTime+时间单位 unit 空闲线程的存活时间
ThreadFactory 线程工厂,用来创建新线程
workQueue 用于存放任务的队列
Handler 处理被拒绝的任务

2.线程池执行流程

2.1 流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MDZVKSon-1593035570853)(G:\workspace\csdn\learn-document\java\concurrent\image-20200623162344913.png)]

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种拒绝策略

8.参考

  • 《Java 并发编程 78 讲》- 徐隆曦
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章