Java 多线程之自定义线程池(ThreadPool)使用方法

这篇具有很好参考价值的文章主要介绍了Java 多线程之自定义线程池(ThreadPool)使用方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、概述

  • 线程池是一种管理和复用线程的机制,它包含一组预先创建的线程,用于执行各种任务。线程池的主要作用是提高多线程应用程序的性能和效率,并提供对线程的生命周期和资源的管理,包括线程的创建、销毁和复用。

  • 本文主要讨论线程池执行器(ThreadPoolExecutor)的用法,在观看本文之前建议先看线程池使用入门。

二、ThreadPoolExecutor 的作用

  • ThreadPoolExecutor 的作用是创建线程池。一般情况下,我们使用 Executors 来创建线程池,使用起来非常简单方便。但是他有一个问题,就是创建池时有很参数需要调整时他就不灵活了。Executors 创建线程池本质上也是使用 ThreadPoolExecutor ,所以我们需要了解 ThreadPoolExecutor ,因为他提供了更多和线程池管理控制功能。

  • 下面是使用 ThreadPoolExecutor 创建线程池的示例:

    ThreadPoolExecutor s = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS, 
            new ArrayBlockingQueue<Runnable>(4), Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy());
    
  • ThreadPoolExecutor 有7个构造函数,每个参数的用途如下:

    • int corePoolSize, 核心线程数量。线程池中的基本线程数,即在没有任务需要执行时线程池的大小。
    • int maximumPoolSize, 最大线程数量。线程池中允许的最大线程数。
    • long keepAliveTime, 线程生存时间。就是线程在多少时间没有执行任务,就释放线程相关资源。
    • TimeUnit unit, 线程生存时间单位。指定 keepAliveTime 的时间单位。
    • BlockingQueue workQueue, 任务队列。用于保存等待执行的任务的队列。
    • ThreadFactory threadFactory, 线程产生的工厂。用于创建新线程的工厂。
    • RejectedExecutionHandler handler 拒绝策略,就是所有线程都在执行且任务满以后的处理办法。
      • Abort 中止策略。是默认的拒绝策略。当任务无法被接受时,会抛出 RejectedExecutionException 异常
      • Discard 丢弃策略。直接丢弃无法执行的任务,不抛出异常也不通知调用者,一般情况下是不能使用的。
      • DiscardOld 丢弃最老的策略。会丢弃队列中等待时间最长的任务,然后尝试将新任务加入队列。
      • CallerRuns 调用者运行策略。不会抛弃任务,而是将任务返回给调用者,由调用者所在的线程执行。

三、自定义线程池工创建工厂

  • 通过实现 ThreadFactory 接口,实现自定义线池创建工厂。

  • 如下,自定义线程创建工厂,在创建线程时设置线程名称。

        private static void  test2()  {
            ThreadFactory  threadFactory = new ThreadFactory(){
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setName( "线程-" + thread.getId()); // 设置一个线程名称,方便异常追踪
                    // 可以在这里设置其他线程属性,例如优先级、是否为守护线程等
                    return thread;
                }
            };
    
            ThreadPoolExecutor s = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<Runnable>(4), threadFactory,
                    new ThreadPoolExecutor.CallerRunsPolicy());
        }
    

四、自定义线程池拒绝策略

  • 通过实现 RejectedExecutionHandler 接口,实现自定义线程池拒绝策略。

  • 如下,我通过自定义线程池拒绝策略,让线程池添加任务数量大于100时,输出一个日志。

    高并发实际应用中你可以记录一个日志文件或数据库,当线程池任务数量小于规定值时重新把任务加入线程池,进行线程池任务恢复,从而防止内存泄露、资源不足等异常产生,保证程序健壮性和稳定性。

        private static void  test1() throws ExecutionException, InterruptedException {
            RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler(){
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    if(executor.getQueue().size() > 100){
                        System.out.println("线程池任务数量大于100了,要不要限制什么的");
                    }
                }
            };
    
            ThreadPoolExecutor s = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<Runnable>(4), Executors.defaultThreadFactory(),
                    rejectedExecutionHandler);
        }
    

五、线程池使用示例

  • 在下面示例中,我创建一个线程池。核心线程数为2个,最大线程数为4个(最多只有4个线程在执行任务),线程空闲存活时间为60秒,使用 ArrayBlockingQueue 保存 Runnable 类型任务,使用默认线程创建工厂和调用者运行拒绝策略。然后添加一个100个任务,每个任务耗时5秒。线程池会执行这些任务,至到结束。文章来源地址https://www.toymoban.com/news/detail-859013.html

        private static void  test3()  {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<Runnable>(4),  Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.CallerRunsPolicy());
    
            for (int i = 1; i <= 100 ; i++) {
                final int id = i;
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        someTask(id);
                    }
                });
            }
        }
    
        private static void  someTask(int id){
            // 这里是一个复杂的业务逻辑(耗时任务)
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("这里是一个复杂的业务逻辑(耗时任务)"+id);
        }
    

到了这里,关于Java 多线程之自定义线程池(ThreadPool)使用方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#基础--线程Thread和线程池ThreadPool

    1. 开启一个线程 ThreadStart 是属于System.Threading 中的一个内置委托 ParameterizedThreadStart 是属于System.Threading 中的一个内置委托 2. 暂停/恢复线程 无法实时的去 “暂停 ” 或者 “恢复” 线程,因为线程是由系统调度执行的,而且中间存在一个延时现象,不可能直接帮你执行 3. 终结

    2024年02月16日
    浏览(22)
  • c++多线程中常用的使用方法

    1)promise(保证)和future的联合使用,实现两个线程的数据传递 //输出结果:myFuture thread receive value is : 30 2) package_task的使用,把任务从新包装起来,案例代码如下: 3)//std::async和std::future一起配合使用 4)//条件变量与互斥量的配合使用方法: 5)互斥量的使用方法: 6)单例

    2024年02月11日
    浏览(21)
  • 使用代理IP池实现多线程爬虫的方法

    目录 前言 代理IP的概念和作用 为什么使用代理IP池 代理IP池的实现步骤 代码实现 注意事项 总结 随着互联网的发展,爬虫技术在各个领域中被广泛应用。然而,目标网站对爬虫的限制也日益严格,例如限制单个IP的请求频率。为了解决这个问题,使用代理IP池成为了一种常见

    2024年01月16日
    浏览(34)
  • vue3使用自定义组件内方法

    使用 defineExpose 来导出方法 script setup 组件时默认不导出属性方法的(类似 java 的 private ),即通过 ref 获取实例是无法访问到自定义的属性和方法,但是可以获取到组件实例。 可以通过 defineExpose 来指定要暴露的方法属性,便可以在外部访问到组件自定义的属性方法了。 当然也

    2024年01月19日
    浏览(25)
  • 【QT】C++和QML使用多线程优化界面切换卡顿的方法

    qt提供了一种声明式语言qml,可以使用一些可视组件以及这些组件之间的交互来描述用户界面,而c++可以只负责后台逻辑的处理,将界面和后台分离开来,由qml来做UI界面,c++负责后端处理,对我个人来说,这样的方式大大的方便了对界面和逻辑的修改和维护; 由于UI界面是工

    2024年01月19日
    浏览(34)
  • JavaSE_day43(多线程单线程区别,图解main方法若是单多线程该如何执行,如何使用多线程2种方式)

    1 A.java  * 学习多线程之前,我们先要了解几个关于多线程有关的概念。          A:进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。          B:线程:线程是进程中的一个执

    2024年02月08日
    浏览(38)
  • STM32引脚定义表以及重映射的使用方法

    首先STM32的引脚图: 1. 表格颜色: 橙色是电源相关引脚。 蓝色是最小系统相关的引脚 绿色是IO口,功能这些引脚。 2. 类型: S代表电源,I代表输入,O代表输出,IO代表输入输出 3.I/O 口电平( 表示它能容忍的的电压 ): FT 是代表能容忍5v电压。 没有FT就代表只能容忍3.3V电压

    2024年02月07日
    浏览(33)
  • WordPress使用自定义文章类型实现任意模板的方法

    本文实例讲述了WordPress使用自定义文章类型实现任意模板的方法。分享给大家供大家参考,具体如下: 这几天在搭建博客的时候,碰到了一个对我来说很棘手的问题。WordPress自带的文章类型只能使用他们特定的模版,而我由于想做一个心情时间轴的板块,所以只能自定义文章

    2023年04月24日
    浏览(35)
  • css自定义字体@font-face的使用方法

    可以设置多个 src 属性,以指定不同的字体资源路径。这样做的目的是为了增强字体的兼容性,以确保在不同的浏览器和设备上都能正常加载字体。 上面设置了三个不同的字体资源路径,分别是 .eot、.woff、.ttf 格式的字体文件,当浏览器无法识别第一个字体文件时,会自动尝

    2024年02月17日
    浏览(37)
  • 【微信小程序】使用自定义字体的三种方法

    小程序官方提供的接口,最便捷的加载字体的方法,不过限制颇多。必须https且同源,canvas等原生组件不支持。注意!!使用本地文件无效,必须使用网络地址。 官方文档:wx.loadFontFace(Object object) | 微信开放文档 演示代码: 传统的css规则,跟loadFontFace限制一样,必须https且同

    2024年02月08日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包