Executor框架与线程池(ThreadPoolExecutor)

Executor框架的组成

组件 作用
Executor 基础接口,仅定义execute(Runnable)方法,用于执行任务。
ExecutorService 扩展Executor,提供任务提交(submit)、线程池关闭(shutdown)等功能。
ScheduledExecutorService 支持定时或周期性任务调度。
ThreadPoolExecutor 最常用的线程池实现类,提供高度可配置的线程池管理。
Executors 工厂类,提供创建常见线程池的快捷方法(如newFixedThreadPool)。

ThreadPoolExecutor的核心机制

  • 线程池的构造参数

    public ThreadPoolExecutor(
       int corePoolSize,          // 核心线程数
       int maximumPoolSize,       // 最大线程数
       long keepAliveTime,        // 空闲线程存活时间
       TimeUnit unit,             // 时间单位
       BlockingQueue<Runnable> workQueue,  // 任务队列
       ThreadFactory threadFactory,        // 线程工厂
       RejectedExecutionHandler handler    // 拒绝策略
    )
  • 任务提交

    • 若当前线程数 < corePoolSize,立即创建新线程执行任务。
    • 若线程数 ≥ corePoolSize,将任务放入workQueue等待。
    • 若队列已满且线程数 < maximumPoolSize,创建临时线程处理任务。
    • 若队列已满且线程数 ≥ maximumPoolSize,触发RejectedExecutionHandler拒绝任务。
  • 线程回收

    • 临时线程(超过corePoolSize的部分)在空闲keepAliveTime后被回收。
    • 核心线程默认不回收,可通过allowCoreThreadTimeOut(true)启用回收。
  • 关键参数详解

    参数 作用与典型值
    corePoolSize 核心线程数(常驻线程),默认长期存活。CPU密集型任务建议设为CPU核心数+1
    maximumPoolSize 最大线程数(含核心线程)。IO密集型任务可设较高值(如2*CPU核心数)。
    keepAliveTime 临时线程空闲存活时间(如30秒)。
    workQueue 任务队列,具体实现: LinkedBlockingQueue:无界队列(需防OOM) ArrayBlockingQueue:有界队列(需合理容量) SynchronousQueue:直接传递队列(高吞吐)
    threadFactory 自定义线程创建逻辑(如命名线程、设置优先级)。
    handler 拒绝策略(当队列和线程池全满时处理新任务): AbortPolicy(默认):抛出RejectedExecutionException CallerRunsPolicy:由提交任务的线程执行任务 DiscardPolicy:静默丢弃任务 DiscardOldestPolicy:丢弃队列最旧任务并重试提交
  • CorePoolSize设置

    • CPU密集型任务(如计算、压缩):

      • 核心线程数 = CPU核心数 + 1
      • 公式:corePoolSize = N + 1(N为CPU核心数),避免线程竞争导致的上下文切换开销。
    • I/O密集型任务(如网络请求、数据库查询):

      • 核心线程数 = CPU核心数 × 2
      • 公式:corePoolSize = N × (1 + 平均I/O等待时间 / 平均计算时间),若无法精确统计,可设为 2N~5N

线程池的创建与使用

方法 实现类 特性
newFixedThreadPool(n) ThreadPoolExecutor 固定大小线程池,无界队列(LinkedBlockingQueue),核心线程数=最大线程数。
newCachedThreadPool() ThreadPoolExecutor 可扩容线程池,最大线程数为Integer.MAX_VALUE,使用SynchronousQueue
newSingleThreadExecutor() ThreadPoolExecutor 单线程池,任务按顺序执行,无界队列。
newScheduledThreadPool(n) ScheduledThreadPoolExecutor 支持定时任务调度。

任务分界与执行策略

任务分界的原则

  • 独立性

    • 无共享状态:任务之间尽量不依赖共享数据,避免同步开销。
    • 示例:将大数组分割为多个子数组,分别计算子数组的和。
  • 粒度平衡

    • 粗粒度:任务过少,无法充分利用多核资源。
    • 细粒度:任务过多,线程管理开销增大。
    • 目标:根据硬件(如CPU核心数)和任务类型(CPU/IO密集型)调整任务粒度。
  • 可组合性:支持将子任务结果合并为最终结果(如ForkJoinPoolRecursiveTask)。

任务分界的方法

  • 数据分片(Data Partitioning)

    • 原理:将数据集划分为多个子集,每个线程处理一个子集。
    • 适用场景:批量数据处理(如统计、图像渲染)。
  • 任务流水线(Pipeline)

    • 原理:将任务拆分为多个阶段,每个阶段由独立线程处理(类似工厂流水线)。
    • 适用场景:多阶段处理(如日志采集 → 清洗 → 存储)。
  • 递归分解(Recursive Decomposition)

    • 原理:将任务递归拆分为更小的子任务,直到达到阈值后顺序执行。
    • 适用场景:分治算法(如归并排序、快速排序)。

执行策略的类型与选择

  • 并行处理(Parallel Processing)

    • 核心思想:将任务分配给多个线程同时执行,充分利用多核CPU。
    • 适用场景:计算密集型任务(如数值计算、图像处理)。
  • 异步执行(Asynchronous Execution)

    • 核心思想:任务提交后立即返回,通过回调或Future获取结果,不阻塞主线程。
    • 适用场景:IO密集型任务(如网络请求、文件读写)。
    • 实现工具CompletableFuture(链式异步编程)、Future + ExecutorService
  • 混合策略

    • 接收请求:使用异步IO(如NIO)非阻塞接收连接。
    • 处理请求:CPU密集型任务交给固定线程池,IO操作使用异步回调。

执行策略的调优技巧

  • 线程池配置

    • 计算密集型:线程数 ≈ CPU核心数(避免过多线程竞争CPU)。
    • IO密集型:线程数 ≈ CPU核心数 × (1 + 平均IO等待时间/计算时间)。
    • 动态调整:根据监控指标(队列长度、活跃线程数)调整线程池参数。
  • 任务队列选择

    • 无界队列(如LinkedBlockingQueue):适合任务量不可控但需快速响应。
    • 有界队列(如ArrayBlockingQueue):避免内存溢出,需配合拒绝策略。
    • 直接传递队列SynchronousQueue):高吞吐,要求线程池足够大。
  • 拒绝策略

    • AbortPolicy:直接抛出异常,默认策略。
    • CallerRunsPolicy:由提交任务的线程执行任务,降低提交速率。
    • DiscardOldestPolicy:丢弃队列中最旧的任务,腾出空间。
    • 自定义策略:记录日志或持久化被拒绝的任务。

任务取消的机制

Future.cancel()方法定义

boolean cancel(boolean mayInterruptIfRunning);
  • 作用:尝试取消任务的执行。

  • 参数mayInterruptIfRunning表示是否允许中断正在执行任务的线程。

  • 返回值

    • true:任务成功取消(任务未启动或已启动且允许中断)。
    • false:任务已结束或无法取消。

cancel()的行为场景

  • 任务尚未启动:任务直接从任务队列中移除,不会执行。

  • 任务正在运行:根据mayInterruptIfRunning参数决定是否中断任务线程:

    • mayInterruptIfRunning=true:向任务线程发送中断信号(设置中断标志位)。
    • mayInterruptIfRunning=false:不中断线程,任务继续执行,但若任务未开始则取消。
  • 任务已完成或已取消:调用cancel()返回false,无实际效果。

任务如何响应取消

  • 协作式中断:任务的取消需要协作,即任务必须主动检查中断状态或处理中断异常。

    • 检查中断标志:在循环或耗时操作中定期调用Thread.interrupted()
    • 处理InterruptedException:在阻塞操作(如Thread.sleep()wait())中捕获异常并退出。

与其他机制对比

机制 原理 优点 缺点
Future.cancel() 基于中断标志的协作式取消 标准化,与线程池集成方便 依赖任务协作,无法强制终止
自定义标志位 通过volatile boolean控制 灵活,无中断依赖 需手动检查,无法中断阻塞操作
Thread.stop() 强制终止线程(已废弃) 立即停止任务 不安全,易导致数据不一致

Java并发编程实战-多线程任务执行的更多相关文章

  1. Java并发编程实战---第六章:任务执行

    废话开篇 今天开始学习Java并发编程实战,很多大牛都推荐,所以为了能在并发编程的道路上留下点书本上的知识,所以也就有了这篇博文.今天主要学习的是任务执行章节,主要讲了任务执行定义.Executor. ...

  2. 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结

    <Java并发编程实战>和<Java并发编程的艺术>           Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...

  3. 【Java并发编程实战】-----“J.U.C”:CyclicBarrier

    在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...

  4. 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock

    ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...

  5. 【java并发编程实战】-----线程基本概念

    学习Java并发已经有一个多月了,感觉有些东西学习一会儿了就会忘记,做了一些笔记但是不系统,对于Java并发这么大的"系统",需要自己好好总结.整理才能征服它.希望同仁们一起来学习 ...

  6. 《java并发编程实战》笔记

    <java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为:  Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...

  7. 《Java并发编程实战》文摘

    更新时间:2017-06-03 <Java并发编程实战>文摘,有兴趣的朋友可以买本纸质书仔细研究下. 一 线程安全性 1.1 什么是线程安全性 当多个线程访问某个类时,不管运行时环境采用何 ...

  8. 《Java并发编程实战》读书笔记一 -- 简介

    <Java并发编程实战>读书笔记一 -- 简介 并发的历史 并发的历史,也是人类利用有限的资源去提高生产效率的一个的例子. 设想现在有台计算机,这台计算机具有以下的资源: 单核CPU一个 ...

  9. Java并发编程实战 01并发编程的Bug源头

    摘要 编写正确的并发程序对我来说是一件极其困难的事情,由于知识不足,只知道synchronized这个修饰符进行同步. 本文为学习极客时间:Java并发编程实战 01的总结,文章取图也是来自于该文章 ...

  10. 【Java并发编程实战】----- AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...

随机推荐

  1. Keepalived基本原理

    本文分享自天翼云开发者社区<Keepalived基本原理>,作者:Ujnrfc Keepalived简介 Keepalived是Linux下一个轻量级别的高可用解决方案.高可用:广义来讲, ...

  2. 基于Linux系统的PXE搭建方法

    本文分享自天翼云开发者社区<基于Linux系统的PXE搭建方法>,作者:t***n 一.底层环境准备 1.安装RedHat7.6系统 2.关闭防火墙和Selinux systemctl s ...

  3. flutter-延时执行

    //1秒后这个i行 Future.delayed(Duration(milliseconds: 1000), () { //代码省略 });

  4. kubesphere应用系列(二)部署有状态服务redis

    前言 在 Kubernetes 中,服务(Service)可以被分为有状态服务和无状态服务,个人认为的区别: 无状态服务是指不依赖于任何持久化状态的服务.它们通常是将请求处理为独立.无关的事务,并且在 ...

  5. 福尼斯焊机TPS320i/TPS400i/TPS500i的焊接特性

    福尼斯焊机设备原理 TPS320i.TPS400i.TPS500i和TPS 600iMIG/MAG电源由微处理器控制,机器人驱动器维修,是完全数字化的逆变器电源. 模块化设计和系统的扩展潜力使其具有高 ...

  6. 解决2023新版Edge浏览器页面加载不出来问题

    如果你遇到2023新版Edge浏览器页面无法加载的问题,可以尝试以下几种解决方法: 检查网络连接:确保你的网络连接正常,可以尝试打开其他网页或使用其他应用程序进行网络测试. 清除浏览器缓存:打开Edg ...

  7. ABC393F题解

    大概评级:绿. 一看到这种题目,就知道肯定是数据结构题,我们首先用一个众所周知的二分来求出 \(pos\) 数组,\(pos_i\) 表示以 \(i\) 结尾的最长上升子序列的大小,然后将询问离线,弄 ...

  8. CTF-CRYPTO-ECC(2)

    CTF-CRYPTO-ECC(2) 椭圆加密 4.BSGS(小步大步法) [HITCTF 2021 ] task.py #Elliptic Curve: y^2 = x^3 + 7 mod N whi ...

  9. go cobra Error: required flag(s) "pkg-name" not set

    Cobra 是一个 Golang 包,它提供了简单的接口来创建命令行程序.同时,Cobra 也是一个应用程序,用来生成应用框架,从而开发以 Cobra 为基础的应用. 使用 cobra init 命令 ...

  10. Content-Encoding:br 是一种什么编码格式?

    一.前言 在之前测试HTTP应答的压缩过程中无意间发现在Google浏览器下出现了 Content-Encoding:br 这种的编码格式,当时我就纳闷了,前面不是一直在研究GZip压缩吗?br压缩又 ...