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

Java教程——线程池和future

Future 详解

1. Future 是什么?

Future 是 Java 中的一个接口(java.util.concurrent.Future),代表异步计算的未来结果。它允许你:

  • 提交任务后立即返回
  • 在需要时检查任务是否完成
  • 获取任务结果(完成后)
  • 取消任务
2. 怎么使用 Future?

通过线程池提交任务:

ExecutorService executor = Executors.newFixedThreadPool(2);// 提交 Callable 任务(有返回值)
Future<String> future = executor.submit(() -> {TimeUnit.SECONDS.sleep(2);return "任务完成";
});// 其他操作...
String result = future.get(); // 阻塞直到结果就绪
3. Future 的作用
  • 异步解耦:主线程不阻塞等待
  • 结果获取:在需要时通过 get() 取结果
  • 任务控制:支持取消和超时
4. Future 和异步的联系

Future 是 Java 中实现异步编程的核心工具

  • 提交任务即异步执行
  • Future 对象作为"凭证",后续凭此获取结果
  • 典型工作流:
    主线程提交任务
    线程池异步执行
    返回 Future
    继续其他操作
    future.get 取结果
5. 异步 vs 并发
异步并发
非阻塞调用多个任务同时推进
关注单任务的非阻塞性关注多任务管理
Future 是异步工具线程/线程池是并发基础
:网络IO不阻塞主线程:同时处理100个请求
6. Future 和线程的关系
  • 依赖关系:Future 需要线程池执行任务
  • 结果载体:线程池返回 Future 作为结果容器
  • 控制中介:通过 Future 控制任务状态(如取消)
7. 复杂任务处理:Future 组合案例
ExecutorService executor = Executors.newFixedThreadPool(3);// 步骤1:获取用户数据(耗时2秒)
Future<String> userFuture = executor.submit(() -> {TimeUnit.SECONDS.sleep(2);return "用户数据";
});// 步骤2:获取订单数据(依赖用户数据)
Future<String> orderFuture = executor.submit(() -> {String user = userFuture.get(); // 阻塞等待前置任务return user + " + 订单数据";
});// 步骤3:获取推荐数据(独立任务)
Future<String> recommendFuture = executor.submit(() -> {TimeUnit.SECONDS.sleep(1);return "推荐数据";
});// 组合最终结果
String result = orderFuture.get() + " | " + recommendFuture.get();
System.out.println("最终结果: " + result); // 用户数据 + 订单数据 | 推荐数据executor.shutdown();
代码解析:
  1. 线程池管理:使用 3 线程池处理并发
  2. 任务依赖
    • orderFuture 依赖 userFuture.get() 阻塞等待
    • recommendFuture 独立执行
  3. 结果合并
    用户任务
    订单任务
    推荐任务
    结果合并
  4. 总耗时 ≈ 最大路径
    • 路径A→B:2秒
    • 路径C:1秒
    • 最终耗时 ≈ 2秒(非3秒)
执行流程:
timelinetitle 任务时间轴(单位:秒)section 线程1用户任务 : 0 - 2订单任务 : 2 - 2(瞬时完成)section 线程2空闲 : 0 - 1订单等待 : 1 - 2section 线程3推荐任务 : 0 - 1

关键点:Future 适合简单依赖,对于复杂依赖链建议使用 CompletableFuture(支持回调、链式操作)

总结

  • Future 本质:异步任务的结果容器
  • 核心价值:分离任务提交与结果获取
  • 适用场景:IO密集型任务、并行计算、服务组合
  • 进阶建议:Java 8+ 使用 CompletableFuture 增强异步编程能力

线程池深度解析

一、线程池是什么?

线程池(Thread Pool)是一种线程管理机制,它预先创建一组可复用的线程,通过任务队列管理待执行任务。其核心组件包括:

任务队列
线程集合
执行任务
任务提交
线程回收
二、线程池的作用
作用维度具体说明优势对比
资源复用避免频繁创建/销毁线程创建线程成本:约1ms/次 vs 复用成本:≈0
流量控制通过队列缓冲突发请求避免服务器过载崩溃
性能提升减少线程切换开销实测:线程复用比新建快5-10倍
统一管理提供状态监控/任务取消比单个线程更易监控控制
三、线程池 vs 线程的关系
维度线程池独立线程
本质线程资源管理器执行的最小单位
生命周期长期驻留(可复用)执行完立即销毁
关系比喻企业的人力资源部具体干活的员工
创建成本一次性创建多次使用每次任务都新建
使用场景高并发任务(1000+)简单单次任务
四、线程池核心参数

Java中创建线程池的完整参数:

ThreadPoolExecutor(int corePoolSize,    // 常驻核心线程数int maximumPoolSize, // 最大线程数long keepAliveTime,  // 空闲线程存活时间TimeUnit unit,       // 时间单位BlockingQueue<Runnable> workQueue, // 任务队列ThreadFactory threadFactory,       // 线程创建工厂RejectedExecutionHandler handler   // 拒绝策略
)
五、线程池执行流程
提交任务
核心线程
是否空闲?
立即执行
队列是否
未满?
任务入队
能否创建
新线程?
创建临时线程
执行拒绝策略
六、四种拒绝策略对比
策略类型触发条件处理方式适用场景
AbortPolicy队列和线程池全满抛出RejectedException严格要求不丢任务
CallerRunsPolicy同上回退给提交者线程执行核心业务场景
DiscardPolicy同上静默丢弃新任务日志采集等非关键任务
DiscardOldestPolicy同上丢弃队首任务并重试实时性要求高场景
七、线程池使用黄金法则
  1. 严禁使用Executors快捷方法

    • 问题:newFixedThreadPool使用无界队列 → 可能导致OOM
    • 正确:手动创建ThreadPoolExecutor
  2. 合理设置队列容量

    • 计算型任务:队列长度设为 2×核心线程数
    • IO密集型:可设置稍大(但需监控队列堆积)
  3. 监控关键指标

    // 重要监控指标
    executor.getActiveCount();    // 活跃线程数
    executor.getQueue().size();   // 队列积压量
    executor.getCompletedTaskCount(); // 完成数量
    
  4. 线程池关闭姿势

    executor.shutdown(); // 平缓关闭
    if(!executor.awaitTermination(60, SECONDS)) {executor.shutdownNow(); // 强制关闭
    }
    
八、实际应用场景
  1. Web服务器:Tomcat线程池(maxThreads=200 + acceptCount=100
  2. 大数据处理:Spark任务调度池
  3. 金融交易:独立线程池处理不同优先级订单
  4. 微服务架构:Hystrix线程池隔离不同服务调用

通过合理使用线程池,某电商系统性能对比:

指标未用线程池优化后线程池提升
QPS12005600367%
CPU波动20%-95%65%-75%更平稳
响应时间300±250ms50±15ms降83%

CompletableFuture 深度指南

http://www.lryc.cn/news/580063.html

相关文章:

  • Spring Boot 应用启动时,端口 8080 已被其他进程占用,怎么办
  • 批量PDF转换工具,一键转换Word Excel
  • Jenkins 介绍
  • 后端密码加密:守护用户数据的钢铁长城
  • [尚庭公寓]06-Redis快速入门
  • 通过 Ansys Discovery CFD 仿真探索电池冷板概念
  • Excel 如何进行多条件查找或求和?
  • WPF 右键菜单 MenuItem 绑定图片时只显示最后一个 Icon
  • 深度分析:Microsoft .NET Framework System.Random 的 C++ 复刻实现
  • c# 使用GADL: Can‘t load requested DLL错误处理
  • PixiJS教程(004):点击事件交互
  • gic 中断触发类型
  • Python 中线程和进程在实际项目使用中的区别和联系
  • FastAPI 小白教程:从入门级到实战(源码教程)
  • 基于Docker构建OrangePi5 SDK环境
  • 使用mindie:2.0.RC2-800I-A2-py311-openeuler24.03-lts制作一个通用的模型推理性能测试的镜像
  • Windows 10/11 PC平台关闭禁用系统自动上传相关隐私数据手册
  • TDengine STMT2 API 使用指南
  • HarmonyOS-ArkUI 手势系列4--多层级手势
  • Spring Boot 中常用的工具类库及其使用示例(完整版)
  • 洛谷P1941 [NOIP 2014 提高组] 飞扬的小鸟
  • 行阶梯形矩阵和行最简形矩阵的区别
  • 【WRFDA教程第十期】混合数据同化(Hybrid Data Assimilation)
  • 【C++复习1】基础篇
  • 负载均衡--常见负载均衡算法
  • 大带宽服务器中冗余技术的功能
  • 【深度解析】Seedance 1.0:重新定义 AI 视频生成的工业级标准
  • 10.双端Diff算法
  • [代码学习] c++ 通过H矩阵快速生成图像对应的mask
  • 嵌入式C语言:指针