热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

三.多线程JUC篇3.15ThreadPoolExecutor

1.构造参数详细讲解corePoolSize:常驻核心线程数,也就是说这是线程池中始终存活的线程,即使是空闲状态,也不会被销

1.构造参数详细讲解


  • corePoolSize:常驻核心线程数,也就是说这是线程池中始终存活的线程,即使是空闲状态,也不会被销毁,除非关闭线程池。但有个特殊,设置了allowCoreThreadTimeout

  • maximumPoolSize:最大线程数,线程池中最多能存活的线程数

  • keepAliveTime:空闲线程存活时间,配合下一个参数unit,当线程池中的线程数量超过corePoolSize,会清空多余空闲线程,以便使线程池数量保持到corePoolSize数量

  • unit: 空闲线程存活时间的单位,如TimeUnit.SECONDS、TimeUnit.MILLISECONDS等

  • workQueue: 工作队列(阻塞队列、等待队列),调用submit方法,任务首先进入此队列中,而不是立即执行,队列的容量决定了能有多少请求被阻塞队列接受

  • threadFactory: 线程工厂,一般使用默认Executors.defaultThreadFactory()即可

  • handler:线程池的拒绝策略。当等待队列已经满了,再也塞不下新的任务;同时,线程池也满了(即达到maximumPoolSize及workQueue满),无法为新任务服务。这时,我们需要拒绝策略机制合理的处理这个问题


2. 任务什么时候被执行

有时候,您会发现提交的任务,并没有被立即执行,只执行了corePoolSize个任务。这个可能会给我们带来困惑,还没有达到maximumPoolSize,怎么还有部分任务不执行呢?其实是新任务进入了workQueue,workQueue没有满。有二种情况下,剩余部分任务会被执行,第一种workQueue满了,第二种线程池中有线程执行完任务后。

  • 初次分配时,线程池会分配corePoolSize数量的线程,用于执行当前提交的任务

  • 任务提交超过corePoolSize数量的部分,会暂时放至workQueue;待线程池中有空闲线程时,会从workQueue取任务

  • 提交的任务过多,以至于workQueue也放下去了,线程池会在分配线程直到maximumPoolSize;如果线程池中的某个线程执行完了,又没有达到keepAliveTime时,会从workQueue取任务

  • 提交的任务更多了,以至于超过了maximumPoolSize和workQueue大小,会执行handler策略

    public class ThreadPoolExecutorBuild {public static void main(String[] args) {ThreadPoolExecutor executorService &#61; (ThreadPoolExecutor)buildThreadPoolExecutor();int activeCount &#61; -1;int queueSize &#61; -1;while(true){if (activeCount !&#61; executorService.getActiveCount() || queueSize !&#61; executorService.getQueue().size()) {System.out.println(executorService.getActiveCount());System.out.println(executorService.getCorePoolSize());System.out.println(executorService.getMaximumPoolSize());System.out.println(executorService.getQueue().size());activeCount &#61; executorService.getActiveCount();queueSize &#61; executorService.getQueue().size();System.out.println("&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;");}}}private static ExecutorService buildThreadPoolExecutor(){ExecutorService executorService &#61; new ThreadPoolExecutor(1, 2,30, TimeUnit.SECONDS,new ArrayBlockingQueue<>(1),r->{Thread t &#61; new Thread(r);return t;},new ThreadPoolExecutor.AbortPolicy());//ToDoreturn executorService;}private static void sleepSeconds(long seconds){System.out.println("* " &#43; Thread.currentThread().getName() &#43; " *");try {TimeUnit.SECONDS.sleep(seconds);} catch (InterruptedException e) {e.printStackTrace();}}
    }

    (1)executorService.execute(()->sleepSeconds(10)); //执行一个任务&#xff0c;线程池为当前任务分配了一个线程&#xff0c;可以发现活跃线程数1&#xff0c;10秒后任务执行完后&#xff0c;//活跃线程数0* Thread-0 *&#61;&#61;&#61;&#61;&#61;14:55:04&#61;&#61;&#61;&#61;&#61;1120&#61;&#61;&#61;&#61;&#61;14:55:14&#61;&#61;&#61;&#61;&#61;0120(2)executorService.execute(()->sleepSeconds(5));executorService.execute(()->sleepSeconds(10)); //执行二个任务&#xff0c;可以发现依然活跃线程数1&#xff0c;但工作队列中有一个任务&#xff0c;5秒后第一个任务执行完&#xff0c;//第二个任务从工作队列中取出并执行&#xff0c;使用了原线程&#xff08;还是Thread-0&#xff0c;因为corePoolSize保证始//终有一个&#xff09;执行任务* Thread-0 *&#61;&#61;&#61;&#61;&#61;14:56:28&#61;&#61;&#61;&#61;&#61;1121* Thread-0 *&#61;&#61;&#61;&#61;&#61;14:56:33&#61;&#61;&#61;&#61;&#61;1120&#61;&#61;&#61;&#61;&#61;14:56:43&#61;&#61;&#61;&#61;&#61;0120(3)executorService.execute(()->sleepSeconds(10));executorService.execute(()->sleepSeconds(5));executorService.execute(()->sleepSeconds(8));//执行三个任务&#xff0c;我们会发现此时线程池分配了二个线程为三个任务&#xff08;因为工作队列满了&#xff0c;所以//分配的线程数超过了corePoolSize&#xff09;&#xff0c;待第三个任务执行完&#xff0c;第二个任务开始执行了* Thread-0 ** Thread-1 *&#61;&#61;&#61;&#61;&#61;15:00:22&#61;&#61;&#61;&#61;&#61;2121* Thread-1 *&#61;&#61;&#61;&#61;&#61;15:00:30&#61;&#61;&#61;&#61;&#61;2120&#61;&#61;&#61;&#61;&#61;15:00:32&#61;&#61;&#61;&#61;&#61;1120&#61;&#61;&#61;&#61;&#61;15:00:35&#61;&#61;&#61;&#61;&#61;0120


3.线程池的关闭


  • submit()、execute()&#xff1a;非阻塞方法&#xff0c;会立即返回&#xff0c;因为任务首次会放置在workQueue&#xff0c;然后线程池在从workQueue取任务执行
  • shutdown()&#xff1a;非阻塞方法&#xff0c;会立即返回
  • shutdownNow()&#xff1a;非阻塞方法&#xff0c;会立即返回
  • awaitTermination()&#xff1a;阻塞方法&#xff0c;接收timeout和TimeUnit两个参数&#xff0c;用于设定超时时间及单位。当等待超过设定时间时&#xff0c;会监测ExecutorService是否已经关闭&#xff0c;若关闭则返回true&#xff0c;否则返回false。一般情况下会和shutdown方法组合使用。

3.1 shutdown和shutdownNow区别

(1) shutdown

  • 开始一个有序的关闭&#xff0c;在关闭中&#xff0c;之前提交的任务会被执行&#xff08;包含正在执行的&#xff0c;在阻塞队列中的&#xff09;
  • 新任务会被拒绝
  • 中断空闲线程
  • 当前方法不会等待之前提交的任务执行结束&#xff0c;可以使用awaitTermination()

(2) shutdownNow

  • 返回正在等待被执行的任务列表
  • 新任务会被拒绝
  • 中断所有线程&#xff08;shutdown只是中断空闲线程&#xff09;

(3) isShutdown
只要调用了这两个关闭方法中的任意一个&#xff0c;isShutdown方法就会返回true

(4) isTerminated
当所有的任务都已关闭后&#xff0c;才表示线程池关闭成功&#xff0c;这时调用isTerminaed方法会返回true

(5) 中断
如果线程中没有sleep 、wait、Condition、定时锁等可中断点&#xff0c;interrupt()方法是无法中断当前的线程的。所以&#xff0c;ShutdownNow()并不代表线程池就一定立即就能退出&#xff0c;它可能必须要等待所有正在执行的任务都执行完成了才能退出

4.监控线程池

(1) 如果在系统中大量使用线程池&#xff0c;则有必要对线程池进行监控&#xff0c;方便在出现问题时&#xff0c;可以根据线程池的使用状况快速定位问题。

(2)可以通过线程池提供的参数进行监控&#xff0c;在监控线程池的时候可以使用以下属性&#xff1a;

  • taskCount&#xff1a;线程池需要执行的任务数量&#xff0c;是个近似值。
  • completedTaskCount&#xff1a;线程池在运行过程中已完成的任务数量&#xff0c;小于或等于taskCount&#xff0c;是个近似值。
  • largestPoolSize&#xff1a;线程池里曾经创建过的最大线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小&#xff0c;则表示线程池曾经满过。
  • poolSize&#xff1a;线程池当前的线程数总量&#xff0c;包括活动的线程与闲置的线程。
  • activeCount&#xff1a;获取活动的线程数。

推荐阅读
  • 题目描述:计算从起点到终点的最小能量消耗。如果下一个单元格的风向与当前单元格相同,则消耗为0,否则为1。共有8个可能的方向。 ... [详细]
  • 本文深入探讨了Go语言中的接口型函数,通过实例分析其灵活性和强大功能,帮助开发者更好地理解和运用这一特性。 ... [详细]
  • Spring Boot + RabbitMQ 消息确认机制详解
    本文详细介绍如何在 Spring Boot 项目中使用 RabbitMQ 的消息确认机制,包括消息发送确认和消息接收确认,帮助开发者解决在实际操作中可能遇到的问题。 ... [详细]
  • 我自己做了一个网站图片的抓取,感觉速度有点慢抓取4000张图片可能得用15分钟左右的时间,我百度看用线程可以加快抓取,然后创建了5个线程抓取,但是5个线程是同步执行同样的操作一个图片就 ... [详细]
  • 优先队列是一种特殊的队列,不遵循先进先出原则。它分为最大优先队列和最小优先队列。最大优先队列总是将当前最大的元素优先出队,而最小优先队列则总是将当前最小的元素优先出队。本文将详细介绍如何使用二叉堆在C#中实现这两种优先队列。 ... [详细]
  • publicclassBindActionextendsActionSupport{privateStringproString;privateStringcitString; ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 如何高效解决Android应用ANR问题?
    本文介绍了ANR(应用程序无响应)的基本概念、常见原因及其解决方案,并提供了实用的工具和技巧帮助开发者快速定位和解决ANR问题,提高应用的用户体验。 ... [详细]
  • 前言:由于Android系统本身决定了其自身的单线程模型结构。在日常的开发过程中,我们又不能把所有的工作都交给主线程去处理(会造成UI卡顿现象)。因此,适当的创建子线程去处理一些耗 ... [详细]
  • SDWebImage第三方库学习
    1、基本使用方法异步下载并缓存-(void)sd_setImageWithURL:(nullableNSURL*)urlNS_REFINED_FOR_SWIFT;使用占位图片& ... [详细]
  • 关于进程的复习:#管道#数据的共享Managerdictlist#进程池#cpu个数1#retmap(func,iterable)#异步自带close和join#所有 ... [详细]
  • 大华股份2013届校园招聘软件算法类试题D卷
    一、填空题(共17题,每题3分,总共51分)1.设有inta5,*b,**c,执行语句c&b,b&a后,**c的值为________答:5 ... [详细]
  • Redis 是一个高性能的开源键值存储系统,支持多种数据结构。本文将详细介绍 Redis 中的六种底层数据结构及其在对象系统中的应用,包括字符串对象、列表对象、哈希对象、集合对象和有序集合对象。通过12张图解,帮助读者全面理解 Redis 的数据结构和对象系统。 ... [详细]
author-avatar
手机用户2602908963
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有