当前位置: 首页 > news >正文

【从零开始学Java | 第四十三篇】线程池(Thread Pool)

目录

前言

一、什么是线程池?

二、Java中的线程池

1.execute()和submit()的区别

①. execute()

②. submit()

2.自定义线程池

①常见拒绝策略

1. AbortPolicy

2. CallerRunsPolicy

3. DiscardPolicy

4. DiscardOldestPolicy


前言

在我们之前学习多线程的时候,使用线程往往使用的是new Thread()->{}.start()创建一个线程并启动,这种方法虽然简单,但是在实际场景并不会使用这种方法,因为一旦任务很多,频繁创建和销毁线程,会带来很大的性能损耗,甚至可能把系统拖垮。所以,Java 提供了一个更合理的线程管理方案:线程池(Thread Pool)

一、什么是线程池?

线程池,顾名思义,就是事先创建好一批线程,统一放到一个池子里进行管理和复用。

当有任务要执行时,不着急创建一个新的线程,而是首先来到线程池看一下有没有空闲的线程可以复用

当任务执行完毕后,线程不会销毁而是返回到线程池,供下一次调用。

核心思想:

  • 预先创建一定数量的线程
  • 把待执行的任务放入任务队列
  • 由线程池中的线程不断从队列中取任务执行
  • 线程执行完成后不销毁,继续复用
  • 通过统一策略控制线程数量和任务处理方式

二、Java中的线程池

Executors是一个工具类,用来快速创建线程池。

Executors.newFixedThreadPool(5); //创建一个有上限的线程池
Executors.newCachedThreadPool(); //创建一个没有上限的线程池

示例:

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); for (int i = 1; i <= 5; i++) { int taskId = i; executorService.execute(() -> { System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行"); }); } executorService.shutdown(); } }

运行效果:

线程池中最多有 3 个线程,同时去处理 5 个任务。线程会被复用,而不是每个任务都新建一个线程。

1.execute()和submit()的区别

在线程池中,提交任务常见有两个方法:

  • execute()
  • submit()

①. execute()

executorService.execute(() -> { System.out.println("执行任务"); });

特点:

  • 只能提交Runnable
  • 没有返回值
  • 更适合“只关心执行,不关心结果”的任务

②. submit()

Future<Integer> future = executorService.submit(() -> { return 100; });

特点:

  • 可以提交RunnableCallable
  • 有返回值
  • 返回Future对象,可以获取执行结果

2.自定义线程池

线程池常用的构造方法如下:

public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler )

corePoolSize(核心线程数):线程池中长期保留的线程数量。当任务到来时,线程池会优先创建线程,直到线程数达到corePoolSize

maximumPoolSize(最大线程数):线程池允许创建的最大线程数量。如果核心线程都在忙,并且队列也已经满了,线程池就会创建非核心线程,直到总数达到maximumPoolSize。

keepAliveTime(非核心线程空闲存活时间):当线程池中的线程数大于核心线程数时,多出来的那些非核心线程,如果空闲时间超过keepAliveTime,就会被回收。

unit(时间单位):keepAliveTime的时间单位。

workQueue(任务队列):当核心线程都在工作时,新来的任务会被放到任务队列中等待执行。

threadFactory(线程工厂):用于创建线程。

handler(拒绝策略):当线程池无法继续接收新任务时,会执行拒绝策略。

①常见拒绝策略

1. AbortPolicy

默认策略。

直接抛出异常:

RejectedExecutionException

适合对任务丢失非常敏感的场景。

2. CallerRunsPolicy

由提交任务的线程自己执行该任务。

这会让提交任务的线程“背压”,减缓任务提交速度。

3. DiscardPolicy

直接丢弃任务,不抛异常。

适合允许部分任务丢失的场景,但风险较大。

4. DiscardOldestPolicy

丢弃队列中最早的任务,然后尝试提交当前任务。

适合对“最新任务更重要”的场景。

http://www.jsqmd.com/news/693291/

相关文章:

  • 批量给文件改名的方法有哪些?这5个实用技巧新手也能秒会
  • 从QT5到QT6:qmake构建QML项目的资源管理机制变迁
  • Linux服务器被疯狂访问?别慌,用iftop和tcpdump快速定位异常流量(附完整排查流程)
  • 别再只跑Demo了!手把手教你用DINOv2的Patch特征做简单的图像前景分割
  • 2026年扬州二甲基硅油选购避坑指南:脱模剂、消泡剂、润滑剂全应用对标评测 - 年度推荐企业名录
  • 别再手动对齐了!用CREO骨架模型做装配,效率提升不止一倍(附四连杆机构实战)
  • 安徽旭安商贸:专业的合肥砖块出售服务商 - LYL仔仔
  • 保姆级教程:在Gazebo 11中为WAM-V无人艇模型添加AprilTag(Ubuntu 20.04环境)
  • 5分钟上手XUnity Auto Translator:为Unity游戏实现实时自动翻译的完整指南
  • 2026年生产日期喷码机选购指南:品质与服务并重的选择 - GrowthUME
  • 如何用lunar-javascript快速搞定农历计算?终极完整指南
  • AI自动化处理Google Sheets数据:Composio与Gemini TTS实战
  • 告别杂乱视图!用pcl_viewer的-multiview和-ax参数高效对比多组点云数据
  • AzerothCore服务端搭建后必做的5件事:从单机到‘准官方’体验优化指南
  • 你的MCP4725 DAC输出不准?可能是这3个硬件坑和2个软件误区(附STM32 F4实测排查指南)
  • 如何快速解锁加密音乐文件:Unlock-Music完整使用指南
  • Elasticsearch架构核心:Node节点详解与角色功能全解析
  • 创业公司选型指南:MIT、Apache、GPL,哪个开源协议能保护你的商业代码?
  • SonarQube 7.8 从部署到实战:一站式代码质量管控指南
  • 从一次内部攻防演练说起:我是如何利用CVE-2017-1000028漏洞“捡到”GlassFish管理员密码的
  • AI 英语教学智能体开发
  • MacBook卡顿别急着换新!用这招‘原地重装’macOS,半小时恢复流畅,数据软件全保留
  • 突破窗口限制:SRWE如何让游戏截图和UI测试效率提升3倍
  • VSCode + Q# 开发环境搭建全链路,深度解析量子模拟器延迟超限的5大根因及修复方案
  • 告别Transformer算力焦虑:用KBNet的KBA模块在图像降噪任务中实现SOTA效果
  • 抖音批量下载终极指南:如何免费高效获取无水印视频内容
  • 2026年乌鲁木齐工装设计与别墅全案定制:龙腾装饰千万级工程承接能力深度评测 - 优质企业观察收录
  • 电话号码精确定位:免费开源工具的实用指南与深度解析
  • 云手机 手游党多开群控的选择
  • PACS系统选型与部署避坑指南:医院影像科技术负责人必看的架构解析