线程池基本概念

本文详细介绍了Java中的线程池机制,包括Executor框架的组成部分(任务、执行器和异步结果),以及ThreadPoolExecutor和ScheduledThreadPoolExecutor的特性、核心参数和拒绝策略。讨论了不同类型的线程池及其适用场景。
摘要由CSDN通过智能技术生成

线程池是一种用于管理和复用线程的机制,它可以在多线程应用程序中有效地处理并发任务。Java中的线程池是通过java.util.concurrent包提供的Executor框架实现的。

Executor 框架

Executor 框架结构主要由三大部分组成:

1.任务

任务是需要在Executor框架中执行的工作单元,可以是实现了Runnable接口或Callable接口的对象。Runnable接口表示一个没有返回值的任务,而Callable接口表示一个有返回值的任务。任务可以封装需要执行的代码逻辑,并可以被提交给执行器进行执行。任务可以是独立的、并行的,或者依赖其他任务的结果。

2.执行器

执行器是Executor框架的核心部分,负责管理和执行任务。它定义了任务的执行策略,包括任务的提交、调度和执行。执行器隐藏了底层线程的创建和管理细节,提供了更高级别的抽象。Java中的Executor接口和ExecutorService接口都是执行器的表示,它们提供了提交任务、执行任务和管理线程池的方法。

  • Executor接口定义了最基本的任务执行方法execute(Runnable command),用于提交一个Runnable任务给执行器。执行器可以根据自己的策略来决定如何执行任务,例如在当前线程执行任务、创建新线程执行任务等。
  • ExecutorService接口继承自Executor接口,提供了更丰富的任务执行方法。除了execute()方法外,还提供了支持任务结果返回的submit()方法,以及关闭线程池的方法,如shutdown()shutdownNow()

Java提供了多个内置的执行器实现,如ThreadPoolExecutorScheduledThreadPoolExecutor,它们提供了可配置的线程池和任务调度功能。

(该图片来自JavaGuide )

3. 异步计算的结果

Future 接口以及 Future 接口的实现类 FutureTask 类都可以代表异步计算的结果。

当我们把 Runnable接口Callable 接口 的实现类提交给 ThreadPoolExecutorScheduledThreadPoolExecutor 执行。(调用 submit() 方法时会返回一个 FutureTask 对象)

(来自 JavaGuide)

ThreadPoolExecutor类

核心参数
  • corePoolSize:核心线程池大小,表示线程池中保持活动状态的线程数量。即使线程处于空闲状态,核心线程也不会被销毁。
  • maximumPoolSize:最大线程池大小,表示线程池中允许存在的最大线程数量。当任务队列已满且活动线程数达到最大线程数时,新的任务将会触发创建额外的线程。
  • keepAliveTime:线程空闲时间,表示线程在没有任务可执行时保持存活的时间。超过该时间,多余的线程将被销毁,直到线程池大小不大于核心线程池大小。
  • unit:时间单位,用于指定keepAliveTime的时间单位。
  • workQueue:任务队列,用于存放等待执行的任务。可以选择不同类型的队列,如ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue等。
  • threadFactory:线程工厂,用于创建新线程。
  • handler:拒绝策略,用于处理无法执行的任务。可以选择使用预定义的拒绝策略,如ThreadPoolExecutor.AbortPolicyThreadPoolExecutor.CallerRunsPolicyThreadPoolExecutor.DiscardPolicyThreadPoolExecutor.DiscardOldestPolicy,或自定义拒绝策略。
拒绝策略
  1. AbortPolicy(默认策略):
    AbortPolicyThreadPoolExecutor的默认拒绝策略。当线程池无法执行任务时,会抛出RejectedExecutionException异常,阻止任务的执行。这个策略会快速失败,通知调用者无法接受新的任务。

  2. CallerRunsPolicy
    CallerRunsPolicy是一种简单的拒绝策略。当线程池无法执行任务时,不会抛出异常,而是将任务返回给提交任务的线程去执行。也就是说,由提交任务的线程自己来执行被拒绝的任务。这样可以降低任务提交者的速度,但也可能导致任务执行的整体速度变慢。

  3. DiscardPolicy
    DiscardPolicy是一种比较简单的拒绝策略。当线程池无法执行任务时,会默默地丢弃无法执行的任务,不做任何处理。这种策略会导致任务被静默丢弃,不会抛出异常,也无法获取到任务的执行结果。

  4. DiscardOldestPolicy
    DiscardOldestPolicy是一种相对较为复杂的拒绝策略。当线程池无法执行任务时,会丢弃最早提交的任务,然后尝试重新提交新的任务。这个策略会优先保留新提交的任务,而不是等待队列中的任务。虽然旧任务被丢弃,但可以保证新任务得到执行。

任务队列
  1. ArrayBlockingQueue
    ArrayBlockingQueue是一个基于数组的有界阻塞队列。它按照先进先出(FIFO)的顺序存储元素,并且具有固定的容量。它的构造方法需要指定队列的容量,一旦队列达到容量上限,后续的插入操作将会阻塞,直到有空间可用。同样,如果队列为空,尝试获取元素的操作也会被阻塞,直到有元素可用。ArrayBlockingQueue是线程安全的,适用于固定大小的线程池。

  2. LinkedBlockingQueue
    LinkedBlockingQueue是一个基于链表的可选界阻塞队列。它同样按照先进先出的顺序存储元素,但是它的容量可以选择性地设置,如果不指定容量,则默认为Integer.MAX_VALUE,即没有容量限制。与ArrayBlockingQueue不同,LinkedBlockingQueue在插入和获取元素时不会阻塞线程,除非队列已满或为空。LinkedBlockingQueue同样是线程安全的,适用于可变大小的线程池。

  3. SynchronousQueue
    SynchronousQueue是一个没有存储空间的阻塞队列。每个插入操作必须等待一个相应的删除操作,反之亦然。它是一种直接传递机制,即生产者线程将元素直接交给消费者线程,而不是将元素存储在队列中。如果没有线程等待接收元素,插入操作将会阻塞,直到有消费者线程准备好接收。同样,如果没有元素可用,尝试获取元素的操作也会被阻塞,直到有生产者线程插入元素。SynchronousQueue通常用于实现线程间的直接传递,适用于固定大小的线程池。

不同类型线程池

  1. FixedThreadPool(固定线程数线程池):
    FixedThreadPool是一个固定大小的线程池,它在初始化时会创建指定数量的线程,并且线程池的大小保持不变。如果所有线程都处于活动状态,新任务将在队列中等待。FixedThreadPool适用于需要控制并发线程数量的场景,例如限制资源使用或避免过度消耗系统资源。

  2. CachedThreadPool(缓存线程池):
    CachedThreadPool是一个可根据需要自动调整大小的线程池。它会根据任务的数量动态地创建线程,如果线程闲置时间超过指定的时间(默认为60秒),则会被终止并从线程池中移除。当有新任务提交时,如果有空闲线程可用,会立即使用它来执行任务,否则会创建新线程。CachedThreadPool适用于任务数量经常变化且需要快速处理的场景。

  3. SingleThreadExecutor(单线程线程池):
    SingleThreadExecutor是一个只有一个工作线程的线程池。它按照先进先出的顺序执行任务,并且保证所有任务都在同一个线程中按顺序执行。如果该线程异常终止,会创建一个新的线程来替代它。SingleThreadExecutor适用于需要顺序执行任务且保证任务按顺序完成的场景。

  4. ScheduledThreadPool(调度线程池):
    ScheduledThreadPool是一个用于执行定时任务和周期性任务的线程池。它可以在指定的延迟时间后执行任务,也可以按指定的时间间隔周期性地执行任务。ScheduledThreadPool适用于需要定时执行任务的场景,例如定时任务调度、定时数据备份等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值