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

java四种内置线程池介绍

目录

    • java线程池概述
      • `Executor`接口
      • `ExecutorService`接口
    • 工具类快速创建线程池
      • FixedThreadPool
      • SingleThreadExecutor
      • CachedThreadPool
      • ScheduledThreadPool
      • 内置线程池总结

java线程池概述

Executor框架是Java提供的一个用于处理并发任务的工具。它简化了线程管理,提供了一个更高层次的任务执行模型。Executor框架的核心组成部分包括Executor接口、ExecutorService接口以及ScheduledExecutorService接口。下面是这些组件的详细介绍:

Executor接口

Executor是Java并发框架中的基础接口,用于提交任务。它有一个方法:

java复制代码
void execute(Runnable command);

这个方法接收一个Runnable对象,并在某个线程中执行它。Executor接口并不提供任务完成后的反馈机制,它只是将任务提交到线程池中执行。

ExecutorService接口

ExecutorService接口继承了Executor接口,提供了一些额外的方法来管理和控制线程池的生命周期。主要的方法包括:

  • submit(Runnable task): 提交一个Runnable任务,并返回一个Future对象,允许你在将来获取任务的执行结果或异常。
  • submit(Callable<T> task): 提交一个Callable任务,并返回一个Future<T>对象,允许你获取任务的结果。
  • invokeAll(Collection<? extends Callable<T>> tasks): 提交一组Callable任务,并返回一个List<Future<T>>对象,表示任务的执行结果。
  • invokeAny(Collection<? extends Callable<T>> tasks): 提交一组Callable任务,并返回第一个成功完成的任务的结果。
  • shutdown(): 启动一次平滑关机,停止接收新任务,但会继续执行已经提交的任务。
  • shutdownNow(): 立即关闭,尝试停止所有正在执行的任务,返回未执行的任务列表。

Executor框架关系图:
在这里插入图片描述

线程池常用方法:

//使用工具类创建线程池
ExecutorService executor1 = Executors.newFixedThreadPool(3);//定义任务
Runnable task = ()->{System.out.println("线程"+Thread.currentThread().getName()+"正在执行");
};executor.excute(XXX); //执行任务,没有返回值
executor.submit(XXX);//执行任务,返回一个Future,用于获取线程的执行情况executor.shutdown();//正常关闭,停止提交新任务,而已提交的任务可以正常执行,非阻塞
executor.shutdownNow();//立即强制关闭,停止提交新任务,正在运行的任务停止,等待队列也销毁,非阻塞
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // 阻塞等待所有任务完成并且shutdown,如果超过到达时间,则返回false

当等待队列是无界队列时,非核心线程会创建吗?

不会,因为非核心线程只有在队列满的时候才会创建,使用了无界队列就相当于默认只有核心线程生效

工具类快速创建线程池

Executors是一个工具类,可以快速创建线程池,它支持四种创建方式

    public static void main(String[] args) {long start = System.currentTimeMillis();ExecutorService executor1 = Executors.newFixedThreadPool(3);//固定线程池,线程不变ExecutorService executor2 = Executors.newCachedThreadPool();//缓冲线程池,自由伸缩ExecutorService executor3 = Executors.newSingleThreadExecutor();//单线程池,FIFOScheduledExecutorService  executor4 = Executors.newScheduledThreadPool (5);// 调度线程池,用于实现定时任务、周期任务}

FixedThreadPool

使用示例:

    private static void runFixedThreadPoolExample() {long startTime = System.currentTimeMillis(); // 记录开始时间// 创建一个固定大小的线程池,线程池大小为3ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);// 提交10个任务到线程池for (int i = 0; i < 10; i++) {final int taskId = i;fixedThreadPool.execute(() -> {System.out.println("FixedThreadPool: 任务 " + taskId + " 在 " + Thread.currentThread().getName() + " 执行");try {Thread.sleep(1000); // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();}});}fixedThreadPool.shutdown(); // 关闭线程池,停止接受新任务try {fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // 等待所有任务完成} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis(); // 记录结束时间System.out.println("FixedThreadPool 运行时长: " + (endTime - startTime) + " 毫秒"); // 打印运行时长}

底层参数:

    public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}

特点:

  • 核心线程数和最大线程数大小一样,没有所谓的非核心线程的空闲时间
  • 阻塞队列为无界队列LinkedBlockingQueue,可能会导致OOM

使用场景:适用于任务数量相对固定且执行周期长的任务。因为创建的都是核心线程,会一直存在,所以如果是短周期任务的话,比较浪费资源。任务并发量不确定的情况也最好不用。

SingleThreadExecutor

使用示例:

private static void runSingleThreadExecutorExample() {long startTime = System.currentTimeMillis(); // 记录开始时间// 创建一个单线程的线程池ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();// 提交5个任务到线程池for (int i = 0; i < 5; i++) {final int taskId = i;singleThreadExecutor.execute(() -> {System.out.println("SingleThreadExecutor: 任务 " + taskId + " 在 " + Thread.currentThread().getName() + " 执行");try {Thread.sleep(1000); // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();}});}singleThreadExecutor.shutdown(); // 关闭线程池,停止接受新任务try {singleThreadExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // 等待所有任务完成} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis(); // 记录结束时间System.out.println("SingleThreadExecutor 运行时长: " + (endTime - startTime) + " 毫秒"); // 打印运行时长}

底层参数:

    public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}

特点:

  • 核心线程数和最大线程数都是1,即只用一个线程去执行所有任务
  • 阻塞队列是无界队列LinkedBlockingQueue,可能会导致OOM

使用场景:当要实现串行执行任务,满足排队执行时

CachedThreadPool

使用示例:

private static void runCachedThreadPoolExample() {long startTime = System.currentTimeMillis(); // 记录开始时间// 创建一个可缓存的线程池ExecutorService cachedThreadPool = Executors.newCachedThreadPool();// 提交10个任务到线程池for (int i = 0; i < 10; i++) {final int taskId = i;cachedThreadPool.execute(() -> {System.out.println("CachedThreadPool: 任务 " + taskId + " 在 " + Thread.currentThread().getName() + " 执行");try {Thread.sleep(1000); // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();}});}cachedThreadPool.shutdown(); // 关闭线程池,停止接受新任务try {cachedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // 等待所有任务完成} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis(); // 记录结束时间System.out.println("CachedThreadPool 运行时长: " + (endTime - startTime) + " 毫秒"); // 打印运行时长}

底层参数:

    public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}

特点:

  • 核心线程数为0,所有线程都是非核心线程,空闲后最多存活60秒
  • 最大线程数为Integer.MAX_VALUE,即无限大,可能会因为无限创建线程,导致OOM
  • 阻塞队列是SynchronousQueue,这个队列的size为1,也就是每提交一个任务,队列都会满,进而就都会创建一个非核心线程

使用场景: 执行并发量大且事件短的小任务需要快速响应的场景

ScheduledThreadPool

使用示例:

    private static void runScheduledThreadPoolExample() {long startTime = System.currentTimeMillis(); // 记录开始时间// 创建一个调度线程池,线程池大小为2ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);// 延迟任务,2秒后执行scheduledThreadPool.schedule(() -> {System.out.println("延迟任务执行: 线程 " + Thread.currentThread().getName() + " 执行了延迟任务");}, 2, TimeUnit.SECONDS);// 周期任务,立即开始执行,每5秒执行一次scheduledThreadPool.scheduleAtFixedRate(() -> {System.out.println("周期任务执行: 线程 " + Thread.currentThread().getName() + " 执行了周期任务");}, 0, 5, TimeUnit.SECONDS);// 让主线程运行一段时间,以便观察周期任务的执行try {Thread.sleep(20000); // 主线程睡眠20秒} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis(); // 记录结束时间System.out.println("ScheduledThreadPool 运行时长: " + (endTime - startTime) + " 毫秒"); // 打印运行时长}

底层参数:

    public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}

特点:

  • 核心线程数可自定义,而最大线程数是Integer.MAX_VALUE,所以也有OOM的风险
  • 阻塞队列是DelayedWorkQueue,按照预期开始时间进行排序
  • scheduleAtFixedRate() :按某种速率周期执行
  • scheduleWithFixedDelay():在某个延迟后执行

使用场景:当要执行延时任务或者周期性任务时

内置线程池总结

总结四种线内置程池都相对比较极端,具体如下:

  • FixedThreadPool:固定线程池,只有核心线程,线程完全固定
  • CachedThreadPool:缓冲线程池,只有非核心线程,线程完全弹性
  • SingleThreadExecutor:单线程池,只能实现排队等待,完全没有并发
  • ScheduledThreadPool:调度线程池,实现延时任务和周期任务,非核心线程数没有上限

注意:《阿里巴巴java开发手册》中明确禁止使用工具类的创建方式,因为线程池的参数不明确,所以不推荐使用工具类创建线程池


http://www.mrgr.cn/news/29167.html

相关文章:

  • Kafka简单实践
  • 如何在OCI上配置并使用OCI GenAI服务的步骤
  • 数据结构——排序(续集)
  • 接口类和抽象类在设计模式中的一些应用
  • 【LeetCode】【算法】11. 盛最多水的容器
  • odoo17 owl 前端 顶部导航栏右侧添加自定义按钮
  • Python面试宝典第49题:字符串压缩
  • DigiDNA推出iMazing 3.0.4,支持Apple Vision Pro
  • 【自动驾驶】决策规划算法(一)决策规划仿真平台搭建 | Matlab + Prescan + Carsim 联合仿真基本操作
  • 用Python实现时间序列模型实战——Day 24: 时间序列中的贝叶斯方法
  • Rust GUI框架Tauri V1 入门
  • C# 链表排序之归并排序
  • Rust GUI框架 tauri V2 项目创建
  • C++ MFC SnowWorld
  • 华为OD机试 - 阿里巴巴找黄金宝箱(V) - 滑动窗口(Python/JS/C/C++ 2024 E卷 100分)
  • 【编译原理】看书笔记
  • C++和OpenGL实现3D游戏编程【目录】
  • WebMagic:强大的Java网络爬虫框架
  • Python绘制基频曲线——实例解析与应用探讨
  • 最新腾讯高精度动作模仿模型MimicMotion分享
  • golang学习笔记27——golang 实现 RPC 模块
  • Golang | Leetcode Golang题解之第414题第三大的数
  • JavaScript:驱动现代Web应用的关键引擎及其与HTML/CSS的集成
  • 一天认识一个硬件之显示器
  • 如何在Java服务中实现数据一致性:事务与锁机制的综合应用
  • 【技术分享】走进Docker的世界:从基础到实战全面解析(Docker全流程)