当前位置:

首页 > 编程开发 > Java线程池工厂使用详解

Java线程池工厂使用详解

如何使用Executors创建线程池?1.使用newFixedThreadPool(intnThreads)创建固定大小的线程池;2.使用newCachedThreadPool()创建可缓存线程池;3.使用newSingleThreadExecutor()创建单线程线程池;4.使用newScheduledThreadPool(intcorePoolSize)创建支持定时和周期任务的线程池。线程池的拒绝策略是什么?如何自定义拒绝策略?默认使用AbortPolicy,其他内置策略包括CallerRunsPol

本文目录

    如何使用Executors创建线程池?1.使用newFixedThreadPool(int nThreads)创建固定大小的线程池;2.使用newCachedThreadPool()创建可缓存线程池;3.使用newSingleThreadExecutor()创建单线程线程池;4.使用newScheduledThreadPool(int corePoolSize)创建支持定时和周期任务的线程池。线程池的拒绝策略是什么?如何自定义拒绝策略?默认使用AbortPolicy,其他内置策略包括CallerRunsPolicy、DiscardPolicy和DiscardOldestPolicy,自定义需实现RejectedExecutionHandler接口并在创建线程池时传入。如何优雅地关闭线程池?调用shutdown()平滑关闭,调用shutdownNow()立即停止任务,结合awaitTermination()等待任务完成或超时处理。如何监控线程池的状态?通过getPoolSize()、getActiveCount()、getCompletedTaskCount()、getTaskCount()和getQueue().size()获取状态信息。Executors创建的线程池有什么缺点?其队列容量过大可能导致OOM,newCachedThreadPool可能创建过多线程耗尽资源,推荐手动使用ThreadPoolExecutor创建以精确控制参数并避免风险。

    Java中Executors类的用途 掌握线程池工厂的创建方法

    Executors类是Java并发包中一个强大的工具类,它简化了线程池的创建和管理,提供了一系列静态工厂方法,帮助开发者快速构建各种类型的线程池,而无需深入了解线程池的底层细节。

    Java中Executors类的用途 掌握线程池工厂的创建方法

    Executors类主要用于创建不同类型的线程池,它隐藏了线程池的复杂性,使开发者能够更专注于任务的执行。

    Java中Executors类的用途 掌握线程池工厂的创建方法

    如何使用Executors创建线程池?

    Executors类提供了多种静态工厂方法,用于创建不同类型的线程池,以下是一些常用的方法:

    • newFixedThreadPool(int nThreads): 创建一个固定大小的线程池,池中始终保持指定数量的线程。如果所有线程都在忙碌,新的任务将被放入队列中等待。

      Java中Executors类的用途 掌握线程池工厂的创建方法
      ExecutorService executor = Executors.newFixedThreadPool(10);
      for (int i = 0; i < 100; i++) {
          executor.execute(new Task(i));
      }
      executor.shutdown();
    • newCachedThreadPool(): 创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需的数量,会自动回收空闲线程。当有新任务提交时,如果没有空闲线程可用,则会创建新的线程。这种线程池非常适合处理大量的短期异步任务。

      ExecutorService executor = Executors.newCachedThreadPool();
      for (int i = 0; i < 100; i++) {
          executor.execute(new Task(i));
      }
      executor.shutdown();
    • newSingleThreadExecutor(): 创建一个单线程的线程池。所有提交的任务都会按照先进先出的顺序执行。如果线程在执行任务时发生异常,会创建一个新的线程来替代它,保证所有任务都会被执行。

      ExecutorService executor = Executors.newSingleThreadExecutor();
      for (int i = 0; i < 100; i++) {
          executor.execute(new Task(i));
      }
      executor.shutdown();
    • newScheduledThreadPool(int corePoolSize): 创建一个可以执行定时任务和周期性任务的线程池。

      ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
      executor.scheduleAtFixedRate(new Task(1), 1, 3, TimeUnit.SECONDS); // 每隔3秒执行一次,延迟1秒后开始执行

    线程池的拒绝策略是什么?如何自定义拒绝策略?

    当线程池的任务队列已满,且线程池中的所有线程都在忙碌时,如果再有新的任务提交,线程池会使用拒绝策略来处理这些任务。Executors创建的线程池默认使用ThreadPoolExecutor.AbortPolicy,该策略会直接抛出RejectedExecutionException异常。

    Java提供了四种内置的拒绝策略:

    • AbortPolicy: 默认策略,直接抛出RejectedExecutionException异常。
    • CallerRunsPolicy: 由提交任务的线程来执行该任务。
    • DiscardPolicy: 直接丢弃该任务,不抛出异常。
    • DiscardOldestPolicy: 丢弃队列中最老的未处理任务,然后尝试执行当前任务。

    当然,你也可以自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可:

    import java.util.concurrent.RejectedExecutionHandler;
    import java.util.concurrent.ThreadPoolExecutor;
    
    public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.out.println("Task " + r.toString() + " rejected from " + executor.toString());
            // 可以添加自定义的拒绝处理逻辑,例如记录日志、持久化任务等
        }
    }

    然后,在创建线程池时,将自定义的拒绝策略传递给ThreadPoolExecutor的构造函数:

    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class Main {
        public static void main(String[] args) {
            int corePoolSize = 5;
            int maxPoolSize = 10;
            long keepAliveTime = 5000;
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    corePoolSize,
                    maxPoolSize,
                    keepAliveTime,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(100), // 任务队列
                    new CustomRejectedExecutionHandler() // 自定义拒绝策略
            );
    
            for (int i = 0; i < 200; i++) {
                executor.execute(new Task(i));
            }
    
            executor.shutdown();
        }
    }

    如何优雅地关闭线程池?shutdown()和shutdownNow()有什么区别?

    关闭线程池是一个重要的步骤,它可以防止资源泄漏。Executors创建的线程池提供了两种关闭方法:shutdown()和shutdownNow()。

    • shutdown(): 平滑关闭线程池。它会阻止新的任务提交,但会等待所有已提交的任务执行完成。

    • shutdownNow(): 立即关闭线程池。它会尝试停止所有正在执行的任务,并返回一个包含所有等待执行的任务的列表。需要注意的是,shutdownNow()方法并不能保证所有任务都会被立即停止,因为某些任务可能正在执行一些无法中断的操作。

    在调用shutdown()或shutdownNow()方法后,可以使用awaitTermination()方法来等待线程池中的所有任务执行完成,或者等待指定的超时时间。

    ExecutorService executor = Executors.newFixedThreadPool(10);
    // 提交任务...
    executor.shutdown(); // 阻止新的任务提交
    try {
        if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { // 等待60秒
            executor.shutdownNow(); // 如果超时,则尝试立即停止所有任务
        }
    } catch (InterruptedException e) {
        executor.shutdownNow(); // 如果当前线程被中断,则尝试立即停止所有任务
    }

    如何监控线程池的状态?

    监控线程池的状态对于诊断性能问题和优化线程池配置非常重要。ThreadPoolExecutor类提供了一些方法来获取线程池的状态信息:

    • getPoolSize(): 返回线程池中的线程数量。
    • getActiveCount(): 返回正在执行任务的线程数量。
    • getCompletedTaskCount(): 返回已完成的任务数量。
    • getTaskCount(): 返回已提交的任务总数。
    • getQueue().size(): 返回任务队列中的任务数量。

    你可以使用这些方法来定期监控线程池的状态,并根据需要调整线程池的配置。例如,如果getQueue().size()持续增长,说明任务提交的速度超过了线程池的处理能力,可能需要增加线程池的大小。

    ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
    // 提交任务...
    
    while (true) {
        System.out.println("Pool Size: " + executor.getPoolSize());
        System.out.println("Active Count: " + executor.getActiveCount());
        System.out.println("Completed Task Count: " + executor.getCompletedTaskCount());
        System.out.println("Task Count: " + executor.getTaskCount());
        System.out.println("Queue Size: " + executor.getQueue().size());
        Thread.sleep(1000); // 每隔1秒打印一次状态信息
    }

    Executors创建的线程池有什么缺点?为什么推荐使用ThreadPoolExecutor手动创建?

    虽然Executors类简化了线程池的创建,但它也存在一些缺点:

    • newFixedThreadPool()和newSingleThreadExecutor(): 它们的任务队列使用了LinkedBlockingQueue,该队列的默认容量是Integer.MAX_VALUE。如果任务提交的速度超过了线程池的处理能力,会导致大量的任务堆积在队列中,最终可能导致OOM(OutOfMemoryError)异常。

    • newCachedThreadPool(): 它可以创建无限数量的线程,如果任务提交的速度过快,可能会创建大量的线程,导致系统资源耗尽。

    因此,阿里巴巴Java开发手册中建议使用ThreadPoolExecutor手动创建线程池,而不是使用Executors类。手动创建线程池可以更精确地控制线程池的参数,例如核心线程数、最大线程数、任务队列的类型和容量、拒绝策略等,从而避免潜在的风险。

    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class Main {
        public static void main(String[] args) {
            int corePoolSize = 5;
            int maxPoolSize = 10;
            long keepAliveTime = 5000;
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    corePoolSize,
                    maxPoolSize,
                    keepAliveTime,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(100) // 任务队列,设置容量
            );
    
            for (int i = 0; i < 200; i++) {
                executor.execute(new Task(i));
            }
    
            executor.shutdown();
        }
    }

    总之,Executors类是Java并发编程中一个非常有用的工具,但需要了解其潜在的风险,并根据实际情况选择合适的线程池创建方式。在大多数情况下,推荐使用ThreadPoolExecutor手动创建线程池,以便更好地控制线程池的参数,并避免潜在的OOM风险。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。