urlname
type
Post
password
SyncToConfluence
category
学习笔记
date
Apr 25, 2024
slug
01HWA0YK3E0KZKS5514MN0J9GG
icon
Button
catalog
summary
tags
JUC
Java
线程池
多线程
cover
Status
BusyTime
Status 1
status
Published
💡
线程池(Thread Pool)是一种基于池化技术的线程管理策略。

带着问题学习

  1. 线程池是什么?
  1. 线程池有几种?
  1. 为什么要用线程池?
  1. 线程池的组成是什么样的?
  1. 不同线程池之间有什么差别?

线程池简介

线程池的好处

  • 提高资源利用率:通过重复使用已创建的线程,减少了线程创建和销毁的开销。
  • 提高响应速度:当任务到达时,任务可以不需要等待线程创建就立即执行,因为线程池中已有线程准备好接收任务。
  • 统一的资源管理和调度:线程池允许系统通过统一的方式来管理线程,避免了对线程的无限制创建。
  • 提供更多的管理策略:线程池提供了如设置最大并发数、选择合适的队列策略、设置线程存活时间等多种管理策略。

线程池相关参数

线程池的工作流程

notion image
notion image

线程池接口及定义

Executor 接口

Executor是最基本的线程池接口,Executor接口非常简单,只有一个execute(Runnable command)方法,用于提交执行任务。

ExecutorService 接口

ExecutorServiceExecutor 接口的一个子接口,定义了线程池的基本方法,所有的线程池都应该实现这个接口

任务提交

  • submit(Callable<T> task)
  • submit(Runnable task)
  • submit(Runnable task, T result)

执行多个任务

  • invokeAll(Collection<? extends Callable<T>> tasks): 执行给定的任务集合,当所有任务完成时,返回保持任务状态和结果的 Future 列表。
  • invokeAny(Collection<? extends Callable<T>> tasks): 执行给定的任务集合,如果最早完成的任务正常终止,则返回其结果。

管理线程池的生命周期

  • shutdown(): 启动一个有序的关闭过程,不再接受新任务,同时等待已提交的任务执行完成。
  • shutdownNow(): 尝试停止所有任务,停止处理正在等待的任务,并返回等待执行的任务列表。(正在执行的任务,没有主动停止的情况下,不会被停止)
  • isShutdown(): 检查线程池是否已经关闭。
  • isTerminated(): 检查关闭后是否所有任务都已完成。

ThreadPoolExecutor类

  • ThreadPoolExecutorExecutorService接口的一个具体实现。
  • 通过传入不同的参数给ThreadPoolExecutor构造函数,可以详细地自定义线程池的行为。
  • 构造函数的参数包括:
    • corePoolSize:核心线程数,即使空闲,线程池中也会保留在池中的线程数。
    • maximumPoolSize:线程池中允许的最大线程数。
    • keepAliveTime:当线程数大于核心线程数时,这是超过该时间的多余空闲线程在终止前等待新任务的最长时间。
    • unitkeepAliveTime 参数的时间单位。
    • workQueue:用于在执行任务之前保存任务的队列。这可以是一个有界队列也可以是无界队列,依赖于具体的需求。
    • threadFactory:用于创建新线程的工厂。
    • handler:当线程池已满且无法接受新任务时的拒绝策略。

Executors

  • Executors是一个工厂类,提供了多种静态方法来创建不同类型的线程池。
  • 相关的创建方法有:
    • newFixedThreadPool(int nThreads)
    • newCachedThreadPool()
    • newSingleThreadExecutor()
    • newScheduledThreadPool(int corePoolSize)
    • newSingleThreadScheduledExecutor()
    • newWorkStealingPool()
    • unconfigurableExecutorService(ExecutorService executor)
    • unconfigurableScheduledExecutorService(ScheduledExecutorService executor)

线程池分类

线程池类型
核心参数
队列类型
线程数量变化
使用场景
特点
FixedThreadPool
固定线程数量
LinkedBlockingQueue
固定线程数
适用于处理任务数量和资源消耗相对稳定的场景
避免频繁创建/销毁线程,提高资源利用率
CachedThreadPool
线程数不固定,空闲线程60秒后终止
SynchronousQueue
根据任务增减
适合执行大量短期异步任务
线程数灵活,空闲时释放资源
SingleThreadExecutor
单线程执行任务
LinkedBlockingQueue
单一线程,不变
需要保证任务顺序执行,如串行化操作
避免多线程同时执行的数据不一致性问题
ScheduledThreadPool
固定线程数量,支持延迟/周期性任务
DelayedWorkQueue
核心线程数固定,非核心线程数可灵活调整(默认无非核心线程)
适用于需要多个后台线程执行周期性任务,保持执行频率或具有延迟的任务
定时或周期性执行任务
 

ThreadPoolExecutor重要参数

任务队列

队列类型
特点
使用场景
注意事项
SynchronousQueue
不存储元素,因此提交到线程池的任务必须立即执行,否则会在新线程中执行或被拒绝。
适用于任务传递,确保任务被立即执行
高线程创建率,可能导致性能问题
LinkedBlockingQueue
阻塞队列,基于链表,通常配置为无界,也可设定界限
适合任务执行速度慢或提交频率高的场景
无界队列可能导致内存耗尽
ArrayBlockingQueue
基于数组的有界阻塞队列
需要限制排队任务数量以避免资源过度使用的场景
需合理设定容量,以平衡内存使用和系统响应能力
PriorityBlockingQueue
支持优先级排序的无界阻塞队列
需要根据任务紧急程度或重要性动态处理任务的场景
任务必须实现Comparable接口,定义优先级比较规则,无界设置可能导致资源耗尽
DelayedWorkQueue
用于存放实现了Delayed接口的元素,只有在延迟期满时才能取走
执行延时或定时任务
管理延时任务时要确保时间的准确性和效率

拒绝策略

拒绝策略
特点
使用场景
注意事项
默认使用此策略的线程池
AbortPolicy
抛出RejectedExecutionException异常
任务不能延迟执行且必须处理拒绝情况时使用
需要适当处理异常,避免程序崩溃
CachedThreadPool, ScheduledThreadPool
CallerRunsPolicy
调用者线程自己执行任务
调用者可以承受任务执行的延迟
可能导致调用者线程性能下降
无默认使用
DiscardPolicy
静默丢弃任务
可以容忍丢失任务的场景
任务可能不被执行,无异常抛出
无默认使用
DiscardOldestPolicy
丢弃队列中最老的任务,尝试提交当前任务
优先处理新任务,旧任务不是关键性的情况
可能导致重要任务丢失,需评估业务对任务的重要性
无默认使用

线程池的状态管理

ThreadPoolExecutor类使用一个int类型的变量来维护线程池的状态和工作线程的数量,这一变量被设计为包含两部分信息:高位表示线程池的状态,低位表示有效线程的数量。

线程池状态

  • RUNNING: 线程池可以接受新任务,也可以处理阻塞队列中的任务。
  • SHUTDOWN: 线程池不接受新任务,但可以处理已添加的任务。
  • STOP: 线程池不接受新任务,不处理队列中的任务,还会尝试中断正在处理的任务。
  • TIDYING: 所有任务都已终止,workerCount(有效线程数)为零,线程池的状态将转变为TIDYING。当线程池变为TIDYING状态时,将会执行terminated()方法。
  • TERMINATED: terminated()方法已完成。

状态转换

  • execute() 方法在提交新任务时检查线程池状态,只有当状态为RUNNING时才会接受新任务。
  • shutdown() 方法使线程池状态变为SHUTDOWN。调用此方法后,线程池将不再接受新任务,但会继续处理已在队列中的任务。
  • shutdownNow() 方法尝试立即停止所有正在执行的任务,并将状态设为STOP,并尝试中断所有正在执行的线程。
  • 状态从TIDYING转换到TERMINATED发生在terminated()方法执行完毕之后。

关闭线程池的方法

关闭方法
特点
适用场景
注意事项
shutdown()
停止接受新任务,已提交的任务继续执行。
希望所有已提交的任务完成时使用。
- 不会立即终止执行中的任务。 - 通常用于应用程序正常结束时。
shutdownNow()
尝试停止所有正在执行的任务,返回未开始执行的任务列表。
需要立即停止所有任务,包括正在执行的任务。
- 可能无法立即停止所有任务。 - 返回列表中的任务未执行。
awaitTermination()
阻塞当前线程,直到线程池完全终止或超时,或线程被中断。
在调用shutdown()shutdownNow()后,等待线程池完全关闭。
- 需要处理InterruptedException。 - 确保在超时后检查线程池是否已完全终止。

注意事项

  • 在关闭线程池后提交任务会导致RejectedExecutionException
  • shutdownNow()可能无法立即停止所有正在执行的任务,因为某些任务可能不响应中断。
  • 在调用awaitTermination()后,应处理InterruptedException,以确保当前线程在等待过程中被中断后可以正确响应。
  • 确保在应用程序关闭或重新启动前,线程池被正确关闭,以避免资源泄露。
FreeSwitch基础Overleaf自部署
Loading...