zoukankan      html  css  js  c++  java
  • ThreadPoolExecutor构造器参数详解

    参数名 作用
    corePoolSize 核心线程池大小
    maximumPoolSize 最大线程池大小
    keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
    TimeUnit keepAliveTime时间单位
    workQueue 阻塞任务队列
    threadFactory 新建线程工厂
    RejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理

    1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。注意:线程不是在ThreadPoolExecutor初始化时创建的,而是在发生外部请求调用的时候才会创建。
    2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行。
    3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务。
    4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
    5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
    6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

    下面通过一个例子我们看一下ActiveThread这个变量是如何变化的

    例子:入参corePoolSize=5,maximumPoolSize=50,workQueue=10000,此时向线程池提交5000次请求

        private static void executeRunnableAnsyTask(ThreadPool threadPool) throws InterruptedException {
            for (int i = 0; i < 5000; i++) {
                threadPool.submit(new RunnableAsynTask(i), "self", new LogErrorFailHandler<>());
            }
        }

    测试程序日志输出:

    初始化状态:ActiveThread:0, corePoolSize:5, poolSize:0, maximumPoolSize:50, TotalTask:0, CompletedTask:0, Queue:0, remainingCapacity:10000
    执行状态1: ActiveThread:5, corePoolSize:5, poolSize:5, maximumPoolSize:50, TotalTask:5000, CompletedTask:90, Queue:4905, remainingCapacity:5095
    执行状态2: ActiveThread:5, corePoolSize:5, poolSize:5, maximumPoolSize:50, TotalTask:5000, CompletedTask:340, Queue:4655, remainingCapacity:5345

    程序刚启动时,还没有提交任务到线程池,此时ActiveThread等于0,说明线程不是在new ThreadPoolExecutor时初始化的,而是发生请求调用的时候才创建

    启动后,我们通过for循环向线程池提交了5000次请求,此时总任务数TotalTask=5000,待执行队列深度为4905=5000-CompletedTask-ActiveThread。可能有人要问,为什么队列积压了4905个待执行任务,活跃线程ActiveThread还是5啊,我不是设置了maximumPoolSize=50吗,应该有50个活跃线程在干活才对啊,是不是JAVA有BUG啊。这个就是大家误区点,有的程序员工作5年都不懂这个。

    请注意看上面提到的第三点:《当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务才会创建新线程执行任务。》

    读懂这句一切豁然开朗,正式因为我们提交5000次请求后,剩余队列大小remainingCapacity=5095,也就是仍然可以再接收5095次请求,正是因为workQueue没有塞满,所有活跃线程数永远都是5,不会创建更多的线程干活。

    下面我们尝试提交15000次请求看看。

        private static void executeRunnableAnsyTask(ThreadPool threadPool) throws InterruptedException {
            for (int i = 0; i < 15000; i++) {
                threadPool.submit(new RunnableAsynTask(i), "self", new LogErrorFailHandler<>());
            }
        }

    日志输出:

    初始化状态:ActiveThread:0, corePoolSize:5, poolSize:0, maximumPoolSize:50, TotalTask:0, CompletedTask:0, Queue:0, remainingCapacity:10000
    执行状态:   ActiveThread:50, corePoolSize:5, poolSize:50, maximumPoolSize:50, TotalTask:10050, CompletedTask:2200, Queue:7800, remainingCapacity:2200
    执行完成:   ActiveThread:0, corePoolSize:5, poolSize:5, maximumPoolSize:50, TotalTask:10050, CompletedTask:10050, Queue:0, remainingCapacity:10000

    可以看到“执行状态”时,活跃线程ActiveThread=50,已经有50个线程同时工作了,为什么是50,而不是51或60呢,因为最大值不能超过设定的maximumPoolSize=50。与此同时可以看到提交的总任务数TotalTask=10050,有人就好奇了,我明明提交了15000次请求啊,怎么少了4950个请求任务。很简单,注意看上面提到的第四点《当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理》,也就是说有4950次请求被线程池拒绝了,线程池能接收的最大任务数=maximumPoolSize+QueueSize。

    看日志

    2020-09-28 13:57:46.040||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=10050)
    2020-09-28 13:57:46.041||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=10051)
    2020-09-28 13:57:46.041||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=10052)
    2020-09-28 13:57:46.042||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=10053)
    2020-09-28 13:57:46.043||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=10054)
    2020-09-28 13:57:46.043||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=10055)
    2020-09-28 13:57:46.043||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=10056)
    
    ... ...
    
    ... ...
    
    ... ...
    
    2020-09-28 13:57:48.466||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=14994)
    2020-09-28 13:57:48.467||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=14995)
    2020-09-28 13:57:48.467||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=14996)
    2020-09-28 13:57:48.468||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=14997)
    2020-09-28 13:57:48.468||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=14998)
    2020-09-28 13:57:48.469||01kfm4egihju|172.16.43.41|funds-starter-web|http-nio-8888-exec-1| INFO | LogErrorFailHandler:13 | 线程池队列已满,执行拒绝策略,任务:RunnableAsynTask(num=14999)

    可以看到线程池按照请求的先后顺序,将最后提交的4950请求拒绝了。

    另外,所有任务执行完成后,线程池会根据我们设置的空闲线程存活时间keepAliveTime回收线程,但并不是所有的空闲线程都会回收,当空闲线程数<=corePoolSize时,将不再回收,即使没有新的任务提交到线程池,也不会回收。

  • 相关阅读:
    mui-popover显示、隐藏弹出菜单的方法
    mui使用总结
    js 原生 document.querySelectorAll document.getElementsByTagName document.querySelector document.getElementById的区别
    mui.min.js:7 Uncaught DOMException: Failed to execute 'send' on 'XMLHttpRequest': Failed to load
    三个div并排
    菜单栏伸缩(附jquery-1.12.1.js)
    验证码生成(点击就更换)
    IDEA算法导包后 import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey;报错
    IDEA加密算法(含所需jar包(commons-codec-1.11.jar ,bcprov-jdk15on-160.jar))
    1,eclipse导入项目jdk版本不一样解决方案 2,java报javax.servlet.jsp cannot be resolved to a type
  • 原文地址:https://www.cnblogs.com/shileibrave/p/13744390.html
Copyright © 2011-2022 走看看