Java线程池笔记

一.为什么使用线程池

如果不使用类似线程池的容器,每当我们需要执行用户任务的时候都要去创建新的线程,线程执行完成之后,线程就会被回收了,这样频繁的创建和小会线程池会浪费大量的系统资源

二.使用线程池的优点?
线程池通过线程复用机制,并对线程进行统一管理

1.降低系统资源消耗,通过复用已经存在的线程,降低线程创建和销毁造成的消耗

2.提高响应速度,当有任务到达时,无需等待新线程的创建就可以立即执行

3.提高线程的可管理行,线程是稀缺资源,如果无限制的创建,不仅会消耗大量系统资源,还会降低系统的稳定性,使用线程池可以进行对线程进行统一分配,调优和监控。

核心组件

Java线程池的核心实现是ThreadPoolExecutor类,主要包含以下几个核心组件:

  1. 工作线程(Worker): 实际执行任务的线程

  2. 任务队列(BlockingQueue): 存放待执行的任务

  3. 线程工厂(ThreadFactory): 用于创建新线程

  4. 拒绝策略(RejectedExecutionHandler): 当任务无法被执行时的处理策略

Java中的线程池实现
Java在java.util.concurrent包中提供了多种线程池的实现,其中最核心的是ExecutorService接口。ExecutorService提供了丰富的线程池管理功能,包括任务的提交、任务的取消、获取任务的执行结果等。Java通过Executors工厂类提供了几种常用的线程池实现:

FixedThreadPool:固定大小的线程池,线程数量在初始化时设定,且不会改变。
CachedThreadPool:可缓存的线程池,线程数量不固定,根据需要动态地创建和销毁线程。
SingleThreadExecutor:单线程的线程池,保证所有任务在同一线程中按顺序执行。
ScheduledThreadPool:支持定时或周期性任务的线程池。

线程池的工作流程
线程池的工作流程大致如下:

任务提交:通过调用ExecutorService的submit()或execute()方法提交任务。
任务缓存:如果当前线程池中的线程数量未达到核心线程数(对于FixedThreadPool和CachedThreadPool),则立即创建新线程执行任务;如果达到核心线程数,则将任务放入工作队列中等待执行。
任务执行:线程池中的线程会不断从工作队列中取出任务并执行。
线程复用:当任务执行完毕后,线程不会立即销毁,而是会回到线程池中等待下一个任务。
线程销毁:如果线程池中的线程数量超过了核心线程数,并且这些线程在指定时间内没有执行任务,则这些线程会被销毁。

任务执行流程

  1. 提交任务:调用execute(Runnable command)方法提交任务

  2. 核心线程处理

    • 如果当前线程数 < corePoolSize,创建新线程执行任务

    • 否则,尝试将任务加入工作队列

  3. 队列处理

    • 如果队列未满,任务入队等待执行

    • 如果队列已满,尝试创建新线程(不超过maximumPoolSize)

  4. 拒绝策略

    • 如果线程数已达maximumPoolSize且队列已满,触发拒绝策略

线程生命周期

  1. 创建:当有新任务提交且当前线程数小于corePoolSize时创建

  2. 执行:从队列获取任务并执行

  3. 回收

    • 核心线程:默认不会回收,除非设置allowCoreThreadTimeOut

    • 非核心线程:空闲超过keepAliveTime后被回收

我们先看看这些参数是什么意思:

  • corePoolSize: 核心线程数,即使空闲也会保留的线程数量

  • maximumPoolSize: 最大线程数,允许创建的最大线程数量

  • keepAliveTime: 非核心线程的空闲存活时间

  • workQueue: 任务队列

  • threadFactory: 线程工厂

  • handler: 拒绝策略

int corePoolSize:该线程池中核心线程数最大值

核心线程:线程池中有两类线程,核心线程和非核心线程。核心线程默认情况下会一直存在于线程池中,即使这个核心线程什么都不干(铁饭碗),而非核心线程如果长时间的闲置,就会被销毁(临时工)。

int maximumPoolSize:该线程池中线程总数最大值 。

该值等于核心线程数量 + 非核心线程数量。

long keepAliveTime:非核心线程闲置超时时长。

非核心线程如果处于闲置状态超过该值,就会被销毁。如果设置allowCoreThreadTimeOut(true),则会也作用于核心线程。

TimeUnit unit:keepAliveTime的单位。

TimeUnit是一个枚举类型。

BlockingQueue workQueue:阻塞队列,维护着等待执行的Runnable任务对象。

常用的几个阻塞队列:

LinkedBlockingQueue:链式阻塞队列,底层数据结构是链表,默认大小是Integer.MAX_VALUE,也可以指定大小。

ArrayBlockingQueue:数组阻塞队列,底层数据结构是数组,需要指定队列的大小。

SynchronousQueue:同步队列,内部容量为0,每个put操作必须等待一个take操作,反之亦然。

DelayQueue:延迟队列,该队列中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素 。

ThreadFactory threadFactory

创建线程的工厂 ,用于批量创建线程,统一在创建线程时设置一些参数,如是否守护线程、线程的优先级等。如果不指定,会新建一个默认的线程工厂。

RejectedExecutionHandler handler

拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略,四种拒绝处理的策略为 :

ThreadPoolExecutor.AbortPolicy:默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常。

ThreadPoolExecutor.DiscardPolicy:丢弃新来的任务,但是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列头部(最旧的)的任务,然后重新尝试执行程序(如果再次失败,重复此过程)。

ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值