news 2026/7/4 9:31:27

什么是线程池?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
什么是线程池?

说说工作中线程池的应用

可以讲在拼团中怎么用的。

3、说一下线程池的工作流程

  • 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的(因为可以选择)。
  • 当调用excute()方法添加一个任务时,线程池会做如下判断:
    • 若正在运行的线程数量小于corePoolSize,则马上创建线程运行这个任务。
    • 若正在运行的线程数量大于或等于corePoolSize,则将这个任务放入队列。
    • 若这时队列满了,而且正在运行的线程数量小于maximumPoolSize,那么还是要创建非核心线程立刻执行这个任务。
    • 若队列满了,且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会根据拒绝策略来应对处理。
  • 当一个线程完成任务时,它会从队列中取下一个任务来执行。
  • 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,若当前正在运行的线程数大于corePoolSize,那么这个线程会被停掉。所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小。

为什么不直接填满到maximyumPoolSize:

  • 内存占用大、上下文切换频繁消耗CPU、同步开销大。
  • 动态扩展的方案只在高峰期临时创建更多线程,是一种“按需分配”的原则:先用少量核心线程处理常规负载,队列缓冲短期突发请求,实在处理不过来才会额外创建线程,空闲时回收多余线程。是为了在响应速度和资源效率之间取得最佳平衡。

4、线程池主要参数有哪些?

  • corePoolSize:初始化线程池中核心线程数,当线程池中线程数小于corePoolSize时,系统默认是添加一个任务才从创建一个线程。
  • maximumPoolSize:表示允许的最大线程数 = 非核心线程数+ 核心线程数。当工作队列也满了,但线程池中总线程数<maximumPoolSize时就会再次创建新的线程。
  • keepAliveTime:非核心线程闲置下来不干活最多存活时间。
  • unit:非核心线程保持存活的时间的单位。
    • TimeUnit.DAYS; 天

      TimeUnit.HOURS; ⼩时

      TimeUnit.MINUTES; 分钟

      TimeUnit.SECONDS; 秒

      TimeUnit.MILLISECONDS; 毫秒

      TimeUnit.MICROSECONDS; 微秒

      TimeUnit.NANOSECONDS; 纳秒

  • workQueue:线程池等待队列
  1. ArrayBlockingQueue:有界队列是一个用数组实现的有界阻塞队列,按FIFO排序量。
  2. LinkedBlockingQueue:基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话就是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQueue;newFixedThreadPool线程池用了这个队列。
  3. DelayQueue:延迟队列是一个任务定时周期的执行的队列。单纯的DealyDueue不保证相同延迟任务的FIFO,但ScheduledThreadPoolExecutor通过添加序列号的方式,确保了FIFO顺序。(任务1还有2秒执行,任务2还有3秒执行,那么任务1排在任务2前面)
    • getDelay()返回距离触发还有多久
    • getDelay() <= 0时,任务才可被取出
    • 队列按触发时间排序,最早该执行的任务在队首
  4. priorityBlockingQueue:是具有优先级的无界阻塞队列。
  5. SynchronousQueue:是一个不存储元素的阻塞队列,每个插入操作必须等另一个线程调用移除操作,否则插入操作一直处于阻塞,吞吐量通常高于

    LinkedBlockingQuene(因为是生产者直接交给消费者,无缓冲,适合突发性、短时任务),newCachedThreadPool线程池使⽤了这个队列。

  • threadFactory:创建一个新线程时用的工厂,可以用来设定线程名、是否为daemon线程等。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// 1. 默认工厂(抽象但可用)

ThreadFactory defaultFactory = Executors.defaultThreadFactory();

// 2. 自定义工厂 - 可以完全控制线程创建过程

ThreadFactory customFactory =newThreadFactory() {

privatefinalAtomicInteger threadNumber =newAtomicInteger(1);

@Override

publicThread newThread(Runnable r) {

Thread t =newThread(r);

t.setName("my-pool-worker-"+ threadNumber.getAndIncrement());

t.setDaemon(false);// 设置为非守护线程

t.setPriority(Thread.NORM_PRIORITY);// 设置优先级

returnt;

}

};

// 3. 在线程池中使用

ThreadPoolExecutor pool =newThreadPoolExecutor(

CORE_POOL_SIZE,

MAXIMUM_POOL_SIZE,

60L, TimeUnit.SECONDS,

newLinkedBlockingQueue<Runnable>(),

customFactory,// 这里传入自定义工厂

newThreadPoolExecutor.CallerRunsPolicy()

);

  • handler:拒绝策略。
  1. AbortPolicy:直接抛出异常,默认使用此策略
  2. CallerFunsPolicy:用调用者所在的线程执行任务
  3. DIscartOldestPolicy:丢弃阻塞队列里最老的任务,也就是队列里最靠前的任务
  4. DiscardPolicy:当前任务直接丢弃
  5. 自定义:实现RejectExecutionHandler接口即可。

5、线程池提交excute和submit有什么区别

(1) execute()

  • 用法:void execute(Runnable command)

  • 特点:

    • 只能提交Runnable 任务

    • 没有返回值

    • 如果任务抛出异常,异常会直接抛到线程中,最终由线程的UncaughtExceptionHandlerafterExecute捕获

(1) execute() 用法:void execute(Runnable command) 特点: 只能提交 Runnable 任务; 没有返回值; 如果任务抛出异常,异常会直接抛到线程中,最终由线程的 UncaughtExceptionHandler 或 afterExecute 捕获。

(2) submit()

  • 用法:

    • Future<?> submit(Runnable task)

    • <T> Future<T> submit(Callable<T> task)

  • 特点:

    • 可以提交Runnable 或 Callable任务;

    • 返回Future对象,可以获取结果、取消任务、捕获异常;

    • 如果任务抛出异常,异常会被封装在Future中,只有调用get()时才会抛出ExecutionException

(2) submit() 用法: Future<?> submit(Runnable task) <T> Future<T> submit(Callable<T> task) 特点: 可以提交 Runnable 或 Callable 任务; 返回 Future 对象,可以获取结果、取消任务、捕获异常; 如果任务抛出异常,异常会被封装在 Future 中,只有调用 get() 时才会抛出 ExecutionException。

6、线程池怎么关闭

(1)shutdown()

  • 行为:停止接收新任务;已提交的任务(正在执行的 + 队列中等待的)会执行完。

  • 特点:平滑关闭,常用方式。

  • 注意:调用后线程池状态会变为SHUTDOWN,不会立刻终止。

(2)shutdownNow()

  • 行为:停止接收新任务,清空队列中的等待任务,并尝试中断正在执行的任务。

  • 返回值:未执行的任务列表。

  • 特点:强制关闭,风险较大(可能造成数据不一致)。

  • 注意:线程是否真正中断,取决于任务代码是否响应中断。

(3)awaitTermination(timeout, unit)

  • 用法:

    pool.shutdown(); if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); }

  • 作用:在调用shutdown()后等待一段时间,如果线程池没有在指定时间内终止,再调用shutdownNow()强制关闭。

  • 特点:常用于“优雅关闭”+“兜底强制关闭”组合。

(4)isShutdown() / isTerminated()

  • isShutdown():调用shutdown()shutdownNow()后返回true

  • isTerminated():所有任务执行结束,线程池完全终止时返回true

  • 可配合轮询检测线程池状态,做收尾逻辑。

7、线程池的线程数应该怎么配置

(1)计算密集型任务

  • 特点:大部分时间消耗在 CPU 运算上。

  • 配置:CPU核数 + 1

  • 理由:核心数保证最大并行度,额外的+1用来应对偶尔的线程挂起(页缺失、GC、上下文切换)。

(2)IO 密集型任务

  • 特点:大部分时间等待 IO(数据库、网络、磁盘等)。

  • 配置:CPU核数 * 2(甚至更高,取决于 IO 等待比例)。

  • 理由:IO 期间线程空闲,更多线程可提升 CPU 利用率。

(3)混合型任务

  • 特点:既包含计算,又包含 IO。

  • 配置方法:

    • 比例分解法:根据任务中 IO 和计算占比,估算最优线程数。

    • 分池法:将任务拆分为计算型和 IO 型,分别放入不同线程池,避免资源竞争。

(4)经验公式(IO 密集型可参考)

线程数=CPU核心数×(1+IO时间计算时间)线程数 = CPU核心数 \times (1 + \frac{IO时间}{计算时间})线程数=CPU核心数×(1+计算时间IO时间​)

  • 如果 IO 占比高,线程数可比 CPU 数大得多。

8、有哪几种常见的线程池

(1)newFixedThreadPool

  • 核心线程数 = 最大线程数 = 固定值

  • keepAliveTime = 0,线程不会被回收。

  • 阻塞队列 = LinkedBlockingQueue(无界队列)

  • 特点:线程数固定,任务多了就排队。

  • 适用场景:适合CPU 密集型任务,线程数可设置为CPU 核心数或略大。

(2)newCachedThreadPool

  • 核心线程数 = 0;最大线程数 =Integer.MAX_VALUE(相当于无限大)。

  • keepAliveTime = 60s,空闲线程超过时间会回收。

  • 阻塞队列 = SynchronousQueue(没有容量,任务直接交给线程执行)

  • 特点:任务多就创建新线程,空闲一段时间自动回收。

  • 适用场景:适合大量并发的短期小任务,但要注意可能导致线程数过多,风险较大。

(3)newSingleThreadExecutor

  • 核心线程数 = 最大线程数 = 1

  • keepAliveTime = 0

  • 阻塞队列 = LinkedBlockingQueue(无界队列)

  • 特点:单线程串行执行,保证任务按照提交顺序(FIFO)执行。

  • 适用场景:适合需要顺序执行任务、或全局只需要一个后台线程的场景。

(4)newScheduledThreadPool

  • 核心线程数 = 指定值;最大线程数 =Integer.MAX_VALUE

  • keepAliveTime = 0

  • 阻塞队列 = DelayQueue

  • 特点:支持定时和周期性任务调度。

  • 适用场景:适合定时执行任务(如心跳检测、周期任务)。

(5)newWorkStealingPool(JDK 1.8+ 新增)

  • 使用ForkJoinPool实现。

  • 核心线程数 = CPU 核心数Runtime.getRuntime().availableProcessors())。

  • 特点:基于“工作窃取算法”,空闲线程可以从其他线程队列里偷任务执行,负载均衡。

  • 适用场景:适合大批量、小任务并行计算(如分治计算)。

9、线程池异常怎么处理?

在使用线程池时,经常会遇到这样的情况:线程池本身没问题,但任务(Runnable/Callable)运行过程中抛出了异常
如果没有额外处理,这些异常可能会被“吞掉”,导致我们难以及时发现问题。

本文总结了常见的几种线程池任务异常处理方式。

(1) 在任务内部 try-catch

pool.execute(() -> { try { int a = 1 / 0; } catch (Exception e) { System.err.println("任务异常: " + e.getMessage()); } });

优点:简单直观,能捕获异常。
缺点:需要每个任务都写try/catch,容易遗漏,不够统一。

(2)submit()+Future.get()

Future<?> future = pool.submit(() -> { int a = 1 / 0; }); try { future.get(); // 会抛 ExecutionException } catch (Exception e) { System.err.println("捕获到异常: " + e.getCause()); }

特点

  • 使用submit()提交任务会返回Future

  • 如果调用get(),会抛出ExecutionException,异常可以被捕获;

  • 但如果不调用get(),异常就会被“吞掉”。

适合需要拿任务返回值的场景。

(3) 设置线程的UncaughtExceptionHandler

ThreadFactory factory = r -> { Thread t = new Thread(r); t.setUncaughtExceptionHandler((thread, e) -> System.err.println(thread.getName() + " 出错了: " + e)); return t; }; ExecutorService pool = new ThreadPoolExecutor( 2, 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), factory ); pool.execute(() -> { int a = 1 / 0; }); //输出示例: pool-1-thread-1 出错了: java.lang.ArithmeticException: / by zero

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/4 9:31:17

2026年全屋智能方案选购参考:海尔智慧家庭实测梳理

最近不少准备装修或者做局部焕新的朋友都在问&#xff0c;全屋智能装起来坑多&#xff0c;要么设备之间不兼容&#xff0c;要么断网就全瘫&#xff0c;要么操作复杂老人小孩用不明白&#xff0c;有没有相对省心的选项&#xff1f;我们整理了目前市场上主流的方案&#xff0c;其…

作者头像 李华
网站建设 2026/7/1 1:41:50

基于51单片机的智能温控风扇 红外遥控 人体感应控制 2(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)

基于51单片机的智能温控风扇 红外遥控 人体感应控制 2(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_降重降ai&#xff09; 特点&#xff1a;一个成品的好坏要看产品功能的完整性&#xff0c;本产品有单片机处理单元&#xff0c;温度检测部分&#xff0c;人机交互液…

作者头像 李华
网站建设 2026/7/4 8:28:05

实战掌握Adobe软件激活:全面解析GenP 3.0破解工具高效配置

实战掌握Adobe软件激活&#xff1a;全面解析GenP 3.0破解工具高效配置 【免费下载链接】Adobe-GenP Adobe CC 2019/2020/2021/2022/2023 GenP Universal Patch 3.0 项目地址: https://gitcode.com/gh_mirrors/ad/Adobe-GenP 还在为Adobe Creative Cloud高昂的订阅费用而…

作者头像 李华
网站建设 2026/7/1 1:39:45

2026公基讲义|行测申论题库|行测申论真题及答案

2026公基讲义|行测申论题库|行测申论真题及答案资料全科都有行测申论真题及答案 PDFhttps://tool.nineya.com/s/1jr3ck8t3 【英语真题】1. "Exam" most probably means&#xff08; &#xff09; A. 考试 B. 计划 C. 图片 D. 文件 答案&#xff1a;A 解析&#xff1a…

作者头像 李华
网站建设 2026/7/1 1:38:19

批量图片翻译视频字幕智能抠图一站式解决跨境电商难题

问题引入在跨境电商领域&#xff0c;卖家们常常面临多重挑战。首先&#xff0c;商品图片的多语言翻译是一项繁琐的任务&#xff0c;尤其是当需要处理大量图片时。例如&#xff0c;一个亚马逊卖家可能需要为200张商品图片添加不同语言的描述&#xff0c;这不仅耗时费力&#xff…

作者头像 李华
网站建设 2026/7/1 1:37:31

Qwen-RobotManip:以统一对齐框架解锁机器人操作基础模型的Scaling Law

通义千问团队提出视觉-语言-动作基础模型新范式&#xff0c;通过表征、运动与行为三维对齐实现跨形态规模化训练 机器人学习基础模型视觉-语言-动作跨形态泛化 核心速览 Qwen-RobotManip 基于 Qwen-VL 构建&#xff0c;采用流匹配扩散变换器&#xff08;DiT&#xff09;作为动…

作者头像 李华