【Java 基础篇】ThreadPoolExecutor 详解

2023-09-20 21:10:14

在这里插入图片描述

多线程编程是现代应用程序开发中的一个重要主题。为了更有效地管理和利用多线程资源,Java 提供了丰富的线程池支持。ThreadPoolExecutor 类是 Java 中用于创建和管理线程池的核心类之一,本文将详细介绍 ThreadPoolExecutor 的使用方法和原理。

线程池的基本概念

在深入探讨 ThreadPoolExecutor 之前,让我们先了解一些线程池的基本概念。

1. 什么是线程池?

线程池是一组维护着多个线程的池子,这些线程可以被反复使用,以执行异步任务。线程池的主要目的是为了管理线程的生命周期,降低线程创建和销毁的开销,提高应用程序的性能和稳定性。

2. 为什么需要线程池?

在多线程应用程序中,创建线程和销毁线程都是比较昂贵的操作,因为它们涉及到操作系统的资源分配。如果每个任务都创建一个新线程,会导致系统开销增加,降低性能。线程池的作用是维护一定数量的线程,并在需要时将任务提交给这些线程执行,避免了线程的频繁创建和销毁。

3. 线程池的优点

使用线程池的好处包括:

  • 提高性能: 可以重复使用线程,避免了线程的频繁创建和销毁。
  • 控制资源: 可以限制线程的数量,避免资源耗尽。
  • 提高响应速度: 可以将任务提交给空闲线程立即执行,提高了任务响应速度。
  • 提高稳定性: 有效控制线程的生命周期,避免线程泄漏和崩溃。

ThreadPoolExecutor 的介绍

ThreadPoolExecutor 是 Java 中用于创建和管理线程池的核心类之一。它提供了丰富的配置选项,可以根据应用程序的需求来创建不同类型的线程池。

构造方法

ThreadPoolExecutor 的构造方法如下:

public ThreadPoolExecutor(
    int corePoolSize,              // 核心线程数,池子中一直保持的线程数量
    int maximumPoolSize,           // 最大线程数,池子中最多可以拥有的线程数量
    long keepAliveTime,            // 非核心线程闲置超时时间
    TimeUnit unit,                 // 超时时间单位
    BlockingQueue<Runnable> workQueue,  // 任务队列,用于存放等待执行的任务
    ThreadFactory threadFactory,    // 线程工厂,用于创建新线程
    RejectedExecutionHandler handler // 拒绝策略,用于处理无法处理的任务
);

接下来,我们将对上述参数进行详细解释:

  • corePoolSize:核心线程数,线程池中一直保持的线程数量。即使这些线程处于空闲状态,也不会被销毁,除非线程池被关闭。这个参数可以理解为线程池的基本容量。

  • maximumPoolSize:最大线程数,线程池中最多可以拥有的线程数量。当任务队列满了,并且正在运行的线程数量达到 corePoolSize 时,线程池会创建新的线程来执行任务,直到达到 maximumPoolSize。如果任务队列满了,且已经达到 maximumPoolSize,则后续任务会根据拒绝策略进行处理。

  • keepAliveTime:非核心线程闲置超时时间。当线程池中的线程数量超过 corePoolSize 时,多余的空闲线程会在等待一定时间后被销毁。这个参数指定了空闲线程的存活时间。

  • unit:超时时间单位,与 keepAliveTime 配合使用。

  • workQueue:任务队列,用于存放等待执行的任务。ThreadPoolExecutor 提供了多种队列实现,例如 LinkedBlockingQueueArrayBlockingQueuePriorityBlockingQueue 等,不同的队列类型适用于不同的场景。

  • threadFactory:线程工厂,用于创建新线程。通常情况下,可以使用默认的线程工厂。

  • handler:拒绝策略,用于处理无法处理的任务。当任务队列已满,并且线程池中的线程数量达到 maximumPoolSize 时,新提交的任务将根据拒绝策略进行处理。常见的拒绝策略包括抛出异常、丢弃任务、丢弃最旧的任务和自定义策略。

线程池的状态

ThreadPoolExecutor 有几种不同的状态,包括以下几种:

  • RUNNING:线程池正在运行,可以接收新任务并处理已有任务。
  • SHUTDOWN:线程池处于关闭状态,不再接受新任务,但会继续处理已有任务,直到任务队列为空。
  • STOP:线程池立即停止,正在执行的任务会被中断,尚未执行的任务会被移出队列。
  • TIDYING:线程池正在整理线程,等待终止状态。
  • TERMINATED:线程池已终止,不再执行任何任务。

工作流程

ThreadPoolExecutor 的工作流程可以简单地描述如下:

  1. 当线程池接收到一个新任务时,首先检查核心线程是否已满,如果未满,则创建一个新的核心线程来执行该任务。

  2. 如果核心线程已满,但线程池中的线程数量未达到最大线程数,则创建一个新线程来执行任务。

  3. 如果线程池中的线程数量已达到最大线程数,将任务添加到任务队列中等待执行。

  4. 如果任务队列已满,并且线程池中的线程数量已达到最大线程数,根据拒绝策略来处理任务。默认情况下,拒绝策略是抛出 RejectedExecutionException 异常。

  5. 当线程池中的某个线程执行完任务后,会从任务队列中获取下一个任务继续执行,直到任务队列为空。

  6. 当线程池处于 SHUTDOWN 状态时,不再接受新任务,但会继续执行已有任务,直到任务队列为空。

  7. 当线程池处于 STOP 状态时,会立即停止所有正在执行的任务,并清空任务队列。

  8. 当线程池处于 TIDYING 状态时,正在执行的任务会继续执行,直到任务队列为空,然后线程池会进入 TERMINATED 状态。

使用 ThreadPoolExecutor

接下来,我们将详细介绍如何使用 ThreadPoolExecutor 创建和管理线程池。

创建 ThreadPoolExecutor

要创建一个 ThreadPoolExecutor,需要调用其构造方法并传递相应的参数。下面是一个示例:

import java.util.concurrent.*;

public class MyThreadPool {
    public static void main(String[] args) {
        // 创建 ThreadPoolExecutor
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2,               // 核心线程数
            4,               // 最大线程数
            30,              // 非核心线程闲置超时时间
            TimeUnit.SECONDS,  // 超时时间单位
            new ArrayBlockingQueue<>(10), // 任务队列
            Executors.defaultThreadFactory(), // 线程工厂
            new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
        );
        
        // 提交任务
        executor.submit(() -> {
            // 任务逻辑
            System.out.println("Hello, ThreadPoolExecutor!");
        });
        
        // 关闭线程池
        executor.shutdown();
    }
}

上面的示例创建了一个 ThreadPoolExecutor,配置了核心线程数为 2,最大线程数为 4,非核心线程闲置超时时间为 30 秒,任务队列为 ArrayBlockingQueue,线程工厂使用默认工厂,拒绝策略为 AbortPolicy(抛出异常)。

提交任务

可以使用 submit 方法将任务提交给线程池执行。任务可以是 RunnableCallable 类型的。

executor.submit(() -> {
    // 任务逻辑
});

关闭线程池

当不再需要线程池时,应该调用 shutdown 方法来关闭线程池。关闭线程池后,将不再接受新任务,但会继续执行已有任务,直到任务队列为空。

executor.shutdown();

定制线程池配置

ThreadPoolExecutor 提供了许多配置选项,可以根据实际需求进行定制。例如,可以设置线程池的拒绝策略、线程池名称、线程池的统计信息等。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize,
    maximumPoolSize,
    keepAliveTime,
    unit,
    workQueue,
    threadFactory,
    handler
);

线程池的状态控制

在某些情况下,可能需要控制线程池的状态,例如暂停线程池、恢复线程池、重新设置线程池参数等。可以通过合理的编码方式来实现这些控制。

总结

ThreadPoolExecutor 是 Java 中用于创建和管理线程池的核心类之一。它提供了丰富的配置选项,可以根据应用程序的需求来创建不同类型的线程池。通过合理配置线程池,可以提高应用程序的性能和稳定性,避免线程创建和销毁的开销,提高任务处理的效率。希望本文对你理解和使用 ThreadPoolExecutor 有所帮助。如果你对多线程编程还有其他问题或需求,欢迎继续阅读相关文档或咨询相关专家。

更多推荐

activiti流程变量

activiti流程变量定义流程变量在Activiti中是一个十分重要的角色,流程运转时,需要靠流程变量,业务系统和activiti结合时少不了流程变量,流程变量就是activiti在管理工作流时根据管理需要而设置的变量。比如:在出差申请流程流转是如果出差天数大于三天则需要总经理审批,否者只需要认识审批,出差天数就可以

AI&DAO,将会引领我们走向何方?

人工智能(AI)和分布式自治组织(DAO)都是区块链赛道的热门项目之一,他们看似在不同的领域独立发展,然而,它们之间也存在着巨大的协同潜力。未来,AI有望成为推动DAO发展的重要动力,同时,DAO也可成为AI的最佳实验场所。DAO的下一波浪潮可能是AIDAO。释放生产力的未来首先,让我们来思考一下,AI如何在DAO中释

创建一个简单的外卖订餐系统

在今天的快节奏生活中,外卖订餐系统已经成为了人们日常生活中不可或缺的一部分。这些系统通过在线点餐和配送服务,为用户提供了便捷的用餐体验。在本文中,我们将创建一个简单的外卖订餐系统,使用Python和Flask框架构建后端,以及HTML、CSS和JavaScript构建前端。技术栈我们将使用以下技术栈来构建这个外卖订餐系

【基本数据结构 三】线性数据结构:栈

学习了数组和链表后,再来看看第三种线性表结构,也就是栈,栈和后边讲的队列一样是一种受限的线性表结构,正是因为其使用有限制,所以对于一些特定的需要操作可控的场合,受限的结构就非常有用。栈的定义我们平时放盘子的时候,都是从下往上一个一个放;取的时候,我们也是从上往下一个一个地依次取,不能从中间任意抽出。栈的结构后进者先出,

Rust认识所有权(4)

认识所有权1.认识所有权2.什么是所有权?2.1程序运行管理运行的方式2.2栈(Stack)和堆(Heap)1.栈(Stack)2.堆(Heap)2.3所有权规则2.4变量作用域2.4String类型2.5内存与分配1.以String类型为参考2.变量与数据交互的方式(一):移动2.1String版本3.变量与数据交互

Linux内核源码分析 (B.4) 深度剖析 Linux 伙伴系统的设计与实现

Linux内核源码分析(B.4)深度剖析Linux伙伴系统的设计与实现文章目录1\.伙伴系统的核心数据结构2\.到底什么是伙伴3\.伙伴系统的内存分配原理4\.伙伴系统的内存回收原理5\.进入伙伴系统的前奏5.1获取内存区域zone里指定的内存水位线5.2检查zone中剩余内存容量是否满足水位线要求5.3内存分配成功之

Vision Transformer(ViT)论文解读与代码实践(Pytorch)

VisionTransformerVisionTransformer(ViT)是一种基于Transformer架构的神经网络模型,用于处理计算机视觉任务。传统的计算机视觉模型如卷积神经网络(CNN)在处理图像任务时取得了很大的成功,但CNN存在一些局限,例如对于长距离依赖的建模能力较弱。ViT通过引入Transform

Windows下SpringBoot连接Redis的正确使用姿势

1.安装Redis1.1通过wsl安装redis参考官方安装文档,需要在wsl2上安装redis服务。注意我们启动redis的方式:Firstway:采用官方文档的方式:sudoserviceredis-serverstart,关闭wsl后redis在后台仍能运行,可以sudoserviceredis-serverst

【web开发】11、文件的上传

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录一、文件上传二、批量上传三、案例:混合数据(form上传)四、启用media五、案例:混合数据(Modelform上传)小结提示:以下是本篇文章正文内容,下面案例可供参考一、文件上传图片文件上传:在form里添加enctype=“multipart

上海长宁来福士P2.5直径4米无边圆形屏圆饼屏圆面屏圆盘屏平面圆屏异形创意LED显示屏案例

长宁来福士广场是一个大型广场,坐落于上海中山公园商圈的核心区域,占地逾6万平方米,其中地上总建筑面积近24万平方米,总投资额约为96亿人民币。LED圆形屏是根据现场和客户要求定制的一款异形创意LED显示屏,进行文字、图片、视频等信息播放,应用在舞台、演播室、酒店、机场、路灯广告等LED场所,根据直径要求,可做成户外室内

Linux Systemd 配置开机自启

博文目录文章目录Systemd操作方式配置方式配置示例参考SystemdSystemd是一个用于启动、管理和监控Linux系统的初始化系统。它是许多现代Linux发行版中默认的初始化系统,取代了传统的SysVinit和Upstart。Systemd的引入在Linux社区引起了一些争议,因为它与传统的初始化系统有很大的差

热文推荐