我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java线程池ThreadPoolExecutor怎么创建

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java线程池ThreadPoolExecutor怎么创建

本篇内容介绍了“Java线程池ThreadPoolExecutor怎么创建”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

简介

ThreadPoolExecutor是一个实现ExecutorService接口的线程池,ExecutorService是主要用来处理多线程任务的一个接口,通常比较简单是用法是由Executors工厂类去创建。

线程池主要解决了两个不同的问题:

  • 在执行大量异步任务时,为了能够提高性能,通常会减少每个任务的调用开销。

  • 提供了一系列多线程任务的管理方法,便于多任务执行时合理分配资源以及一些异常情况的处理。每个ThreadPoolExecutor还维护一些基本统计信息。例如:已完成任务的数量,当前获得线程数等。

Java线程池ThreadPoolExecutor怎么创建

参数说明

ThreadPoolExecutor提供了几个核心参数,方便开发人员根据具体场景合理分配线程资源。

  • corePoolSize:核心线程数,在线程池创建时就已初始化好的n个核心线程,即使线程空闲着也会一直保留在线程池中不被销毁,除非调用线程池方法设置了java.util.concurrent.ThreadPoolExecutor#allowCoreThreadTimeOut(true)(允许核心线程超时销毁)。

  • maximumPoolSize:线程池允许存在最大线程数。

  • keepAliveTime:当线程数大于核心线程数时,多余的线程在执行任务结束后等待新任务的最大等待时间。

  • unitTimeUnit类型,是keepAliveTime多余线程最大空余时间单位。

  • workQueue:必须指定一个阻塞队列,在线程池执行execute方法时新进来的任务在执行前都会保留到此队列里进入等待。

  • threadFactory:创建线程的工厂,默认采用Executors.defaultThreadFactory()创建线程。

  • handler:拒绝策略,当最大线程数已占满,且队列已满,此时线程池将触发拒绝策略,对新进来的任务做拒绝处理,具体的处理方案在后面详细分析(默认使用java.util.concurrent.ThreadPoolExecutor.AbortPolicy直接抛出异常拒绝处理)。

注:maximumPoolSize如果大于corePoolSize,则多出的部分线程数只有在阻塞队列workQueue占满时才会创建核心线程之外的线程去执行任务,如果我们设置的阻塞队列为无界队列(默认大小为Integer.MAX_VALUE),则队列永远无法占满,就不会去创建额外的线程进行工作,一般情况如果任务数足够,那么也是在队列大小还没达到Integer.MAX_VALUE时就已经出现内存溢出了。Executors线程池工厂中的newFixedThreadPool()、newSingleThreadExecutor()方法就是使用了无界队列LinkedBlockingQueue,防止内存溢出在日常开发过程中一般是不建议直接去使用Executors去创建线程池。

如何创建线程池

上面我们提到的可以使用Executors工厂直接创建线程池,但是Executors提供的创建线程池都是不可控的,我们还是得按自己的业务做好分析自定义一个线程池。

以下是线程池创建的一个案例:

@Slf4j@Configurationpublic class ThreadPoolConfig {    @Value("${threadPool.corePoolSize:8}")    private int corePoolSize;    @Value("${threadPool.maximumPoolSize:16}")    private int maximumPoolSize;    @Value("${threadPool.keepAliveTime:60}")    private int keepAliveTime;    @Value("${threadPool.queueSize:99999}")    private int queueSize;    @Bean    public ThreadPoolExecutor testExecutor() {        LinkedBlockingQueue queue = new LinkedBlockingQueue(queueSize);        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,                 TimeUnit.SECONDS, queue, getThreadFactory(), getRejectedExecutionHandler());    }        private ThreadFactory getThreadFactory() {        return new ThreadFactory() {            @Override            public Thread newThread(Runnable r) {                log.info("===> Create new thread ...");                return new Thread(r);            }        };    }        private RejectedExecutionHandler getRejectedExecutionHandler() {        return new RejectedExecutionHandler() {            @Override            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {                // 继续往队列里添加任务,这里只是一个案例,这种方式并不友好,会抛出队列已满的异常                log.info("===> Handler runnable ......");                executor.getQueue().add(r);            }        };    }}

application.properties配置文件

threadPool:  corePoolSize: 8  maximumPoolSize: 16  keepAliveTime: 60  # 为方便测试这里我们配置队列数小一点  queueSize: 99

由以上的线程池配置,我们写一个demo测试一下:

Java线程池ThreadPoolExecutor怎么创建

截取部分运行日志:

  • 红框我们可以看到执行到了线程创建工厂部分代码块

  • 蓝色框日志我们可以看到largestPoolSize=11,这是由于我们配置的maximumPoolSize=16 > corePoolSize=8,我们demo执行的是110个任务并发,队列大小是99,由此分析得出(需要额外出创建线程数 = 并发任务总数110 - 核心线程数8 - 队列大小99 = 3),所以线程池在队列已满时会多创建3个线程用于执行任务,在达到keepAliveTime配置的最大空闲时间后这3个线程即会自动销毁。

Java线程池ThreadPoolExecutor怎么创建

注:可能有的同学会想线程池使用后需要销毁吗?在这里补充一下,如果我们是作为局部变量创建出来的线程池(如:在执行的方法内使用Executors.newFixedThreadPool(10)创建临时的线程池),这种情况我们用完就必须将它立即销毁,否则主线程就会一直处于运行状态。如果是全局配置的线程池,那么就是为整个系统中诸多业务提供使用的,这种就不需要对线程池做销毁,因为一旦销毁了其他的任务就无法继续使用该线程池执行任务。

  • 销毁线程池主要有两种方式:

    • shutdown():此方法对线程池做销毁,线程池会优先将剩余未完成的任务执行完才会执行销毁任务。

    • shutdownNow():此方法会对线程池做立即销毁,无论线程池中的任务是否执行完成。

拒绝策略

通常我们在配置好有限队列大小后,就会有可能出现队列占满的情况,这时候我们的拒绝策略就会起到作用,接下来我们就来分析一下RejectedExecutionHandler接口具体有哪一些实现方式:

  • AbortPolicy:线程池的默认拒绝策略,在JDK提供的ThreadPoolExecutor线程池中有一个默认线程池变量private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();作为默认拒绝策略,查看如下图源码可知它就是直接抛出RejectedExecutionException异常,并且会直接丢弃当前任务,如果担心异常影响后续任务执行开发人员需自行捕获异常处理

Java线程池ThreadPoolExecutor怎么创建

  • CallerRunsPolicy:只要在当线程池未被销毁的情况下,不丢弃任务直接使用主线程(调用线程池执行的线程)执行该任务。因为该策略是由主线程直接执行任务的,所以不建议在并发度高的情况下使用,建议在并发度较低且任务不允许失败的情况下才使用此策略

Java线程池ThreadPoolExecutor怎么创建

  • DiscardPolicy:直接丢弃当前任务,不做任何处理。直接丢弃任务的情况下,开发人员也无法排查到哪些任务被丢弃掉,一般不建议使用,除非是无关紧要的任务即使丢弃也无所谓的。

Java线程池ThreadPoolExecutor怎么创建

  • DiscardOldestPolicy:在线程池未被销毁的情况下,丢弃最早进入队列的一个任务(即最久未执行的任务),然后再重新将此任务加入线程池,在此策略下需注意被丢弃的任务的重要性,如果任务不重要可直接丢弃。

Java线程池ThreadPoolExecutor怎么创建

  • 自定义策略:在以上JDK提供的四种默认拒绝策略之外,我们还可以通过自定义的方式来处理被拒绝的任务。如果担心任务被拒绝或者被丢弃造成不可预估的问题,在时效性没有太大要求的情况下我们可以先将任务内容转换成数据入库做好日志记录,后续可以使用定时任务或者通过MQ消息延迟处理。由以上的线程池配置Demo中的拒绝策略改造伪代码如下:

private RejectedExecutionHandler getRejectedExecutionHandler() {    return new RejectedExecutionHandler() {        @Override        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {            // 伪代码            log.info("===> 可根据任务的重要性区分对待,将任务做转换入库延迟处理 ......");        }    };}

“Java线程池ThreadPoolExecutor怎么创建”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java线程池ThreadPoolExecutor怎么创建

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java线程池ThreadPoolExecutor怎么创建

本篇内容介绍了“Java线程池ThreadPoolExecutor怎么创建”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!简介ThreadPo
2023-07-02

怎么在java中使用ThreadPoolExecutor创建一个线程池

这篇文章给大家介绍怎么在java中使用ThreadPoolExecutor创建一个线程池,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发
2023-06-14

Java多线程 - 创建线程池的方法 - ThreadPoolExecutor和Executors

文章目录 线程池(重点)线程池介绍实现线程池的方式方式一: 实现类ThreadPoolExecutorThreadPoolExecutor构造器的参数线程池处理Runnable任务线程池处理Callable任务 方式二:
2023-08-30

java线程池ThreadPoolExecutor类怎么用

这篇文章将为大家详细讲解有关java线程池ThreadPoolExecutor类怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许
2023-06-29

Java线程池如何创建

本文小编为大家详细介绍“Java线程池如何创建”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java线程池如何创建”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。线程池的好处可以实现线程的复用,避免重新创建线程和
2023-06-29

怎么理解ThreadPoolExecutor线程池技术

本篇文章为大家展示了怎么理解ThreadPoolExecutor线程池技术,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java是一门多线程的语言,基本上生产环境的Java项目都离不开多线程。而线程
2023-06-19

怎么在Java并发包中使用ThreadPoolExecutor线程池

这篇文章给大家介绍怎么在Java并发包中使用ThreadPoolExecutor线程池,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、线程池简介线程池的使用主要是解决两个问题:①当执行大量异步任务的时候线程池能够提供
2023-06-15

Python之ThreadPoolExecutor线程池问题怎么解决

本文小编为大家详细介绍“Python之ThreadPoolExecutor线程池问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python之ThreadPoolExecutor线程池问题怎么解决”文章能帮助大家解决疑惑,下面跟
2023-07-05

python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池怎么使用

这篇文章主要介绍了python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python中ThreadPoolE
2023-07-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录