【Java 多线程】线程池 —— 详解线程池原理和使用

Java线程池是运用最多的并发框架,学号多线程以及合理的使用多线程可以带来很大的好处,今天就来一起学习线程池相关的知识吧!

一、线程池的实现原理

当向线程池提交一个任务后,线程池会怎么做呢?

  1. 首先线程池会在核心线程corePoolSize中找是否都在执行任务,如果不是,就创建一个新的线程来分执行这个任务
  2. 如果核心线程都在执行任务,此时线程池判断工作队列BlockingQueue是否已满,如果没满,就把这个任务加到工作队列中
  3. 如果工作队列也满了,线程池就判断所有线程池中的线程maximumPoolQueue是否都在工作,如果不是,就创建一个新的工作线程来执行任务
  4. 如果都满了,那就会交给饱和策略去处理这个任务

可以结合流程图更好理解:
在这里插入图片描述
接下来展示一张在线程池中的执行流程图:
(图源自《Java并发编程的艺术》)
在这里插入图片描述
线程池在线程中执行任务分为两种情况:

  • execute()方法中创建一个线程,让这个线程执行任务
  • 这个线程执行完任务后,回反复的从BlockingQueue获取任务来执行

二、使用线程池

1. 使用线程池的好处

在开发中,合理的使用线程池可以带来很大的好处:

  1. 降低资源消耗,通过重复的利用以及创建的响线程降低线程创建和销毁的消耗
  2. 提高响应速度,当任务到达时,任务不需要等待线程创建就可以执行
  3. 提高线程的可管理性,如果无线的创建线程,不仅会消耗系统的资源,还会降低系统的稳定性,使用线程池可以进行统一的分配和监控。

2.线程池的创建

我们可以通过ThreadPoolExecutor来创建一个线程池
在这里插入图片描述
这是它拥有的构造方法们,我们来看看这些参数分别是什么:

  1. corePoolSize —— 线程池的基本大小:当提交一个任务到线程池是,线程池会创建一个线程来执行任务,即使其它空闲的基本线程能够执行新任务也会创建线程,等到任务数大于线程池基本大小时就不再创建。
  2. maximumPoolSize —— 线程池中允许的最大线程数 ,如果任务队列满了并且已经创建的线程小于最大线程数,则线程池会再创建新的线程执行任务。
  3. keepAliveTime —— 当线程数大于核心时,这是多余的空闲线程在终止之前等待新任务的最大时间。 超过这个时间线程就会被终止
  4. unit —— keepAliveTime参数的时间单位 ,可选单位有:天、小时、分钟、毫秒、微秒、纳秒
  5. workQueue —— 在执行任务之前用于保存任务的队列。 这个队列只会保存execute方法提交的Runnable任务。
    可以选择以下几个阻塞队列:
    (1) ArrayBlockingQueue: 一个基于数组结构的有界阻塞队列,按先进先出对元素排序
    (2) LinkedBlockingQueue:一个基于链表结构的阻塞队列,按先进先出排序元素,吞吐量高于ArrayBlockingQueue
    (3)PriorityBlockingQueue:一个具有优先级的无限阻塞队列
  6. handler —— 执行被阻止时使用的处理程序,因为达到线程限制和队列容量
    有以下四种饱和策略(拒绝策略):
    (1)AbortPolicy:直接抛出异常
    (2)CallerRunsPolicy:只用调用者所在的这个线程来运行任务
    (3)DiscardPolicy:不处理,丢弃掉,。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。
    (4)DiscardOldestPolicy:丢弃掉队列中最老的一个任务,执行当前任务
    默认拒绝策略为AbortPolicy

3. 向线程池提交任务

有两种方式向线程池提交任务分别是execute()submit()方法
execute()方法用于提交不用返回值的任务,所以无法判断任务是否被线程池执行成功。它的参数是一个Runnable的实例。
submit()方法用于提交需要返回值的任务。线程会返回一个future类型的对象,通过这个对象可以判断任务是否执行成功。

4. 关闭线程池

可以通过调用线程池的shutdown()或者shutdownNow()来关闭线程池,它的原理是遍历线程池中所有的线程,然后逐个调用线程的interrupt()方法中断线程,所以无法响应中断的任务有可能永远无法终止。
二者的区别是:
shutdownNow()首先iang线程池的状态设为STOP,然后尝试停止所有正在执行或暂停的线程,并返回等待执行任务的列表。
shutdown()知识将线程池的状态设置为SHUTDOWN,然后中断所有没有正在执行的任务。

通常调用shutdown()方法关闭线程池,如果线程池中的任务不一定要执行完,可以调用shutdownNow()方法。

唠唠叨叨
这就是线程池的一些基本知识,更多的还是要在实践中慢慢体会,本文参考《Java并发编程的艺术》一书,有任何问题欢迎评论指正,也欢迎点赞关注一起进步。

猜你喜欢

转载自blog.csdn.net/Moo_Lavender/article/details/105144566