当前位置:首页 > 经验 >

线程池架构原理图解(线程池工作原理及方法)

来源:原点资讯(www.yd166.com)时间:2022-11-03 05:27:26作者:YD166手机阅读>>

上篇《》文章末尾,有朋友留言提到文中的场景是IO密集型操作,不是CPU密集操作,不需要使用线程池,我猜这位朋友可能想表达的是IO密集且阻塞时间久的不要使用线程池方案解决。IO密集型在控制好同步处理时间或阻塞等待的条件下是可以使用线程池的,不知道这么描述是否合理,有高见的大佬可以继续留言讨论。

关注过我更新频率的朋友会发现有好几天没有上新内容了,原因有二,一是最近真的太忙了,项目催的紧,程序员哪有不加班是吧;另一个是我正在梳理技能图谱,后续的内容更新会根据这个图谱来,还在进行中,有兴趣的朋友持续关注下我和我的github:wind7rui,持续更新哦!好了,开始我们今天的话题~线程池。注意:下方多图高能预警,建议先收藏后阅读,防止走丢!

为什么要使用线程池

平时讨论多线程处理,大佬们必定会说使用线程池,那为什么要使用线程池?其实,这个问题可以反过来思考一下,不使用线程池会怎么样?当需要多线程并发执行任务时,只能不断的通过new Thread创建线程,每创建一个线程都需要在堆上分配内存空间,同时需要分配虚拟机栈、本地方法栈、程序计数器等线程私有的内存空间,当这个线程对象被可达性分析算法标记为不可用时被GC回收,这样频繁的创建和回收需要大量的额外开销。再者说,JVM的内存资源是有限的,如果系统中大量的创建线程对象,JVM很可能直接抛出OutOfMemoryError异常,还有大量的线程去竞争CPU会产生其他的性能开销,更多的线程反而会降低性能,所以必须要限制线程数。

既然不使用线程池有那么多问题,我们来看一下使用线程池有哪些好处:

  • 使用线程池可以复用池中的线程,不需要每次都创建新线程,减少创建和销毁线程的开销;
  • 同时,线程池具有队列缓冲策略、拒绝机制和动态管理线程个数,特定的线程池还具有定时执行、周期执行功能,比较重要的一点是线程池可实现线程环境的隔离,例如分别定义支付功能相关线程池和优惠券功能相关线程池,当其中一个运行有问题时不会影响另一个。
如何构造一个线程池对象

本文内容我们只聊线程池ThreadPoolExecutor,查看它的源码会发现它继承了AbstractExecutorService抽象类,而AbstractExecutorService实现了ExecutorService接口,ExecutorService继承了Executor接口,所以ThreadPoolExecutor间接实现了ExecutorService接口和Executor接口,它们的关系图如下。

线程池架构原理图解,线程池工作原理及方法(1)

一般我们使用的execute方法是在Executor接口中定义的,而submit方法是在ExecutorService接口中定义的,所以当我们创建一个Executor类型变量引用ThreadPoolExecutor对象实例时可以使用execute方法提交任务,当我们创建一个ExecutorService类型变量时可以使用submit方法,当然我们可以直接创建ThreadPoolExecutor类型变量使用execute方法或submit方法。

ThreadPoolExecutor定义了七大核心属性,这些属性是线程池实现的基石。

线程池架构原理图解,线程池工作原理及方法(2)

corePoolSize(int):核心线程数量。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到任务队列当中。线程池将长期保证这些线程处于存活状态,即使线程已经处于闲置状态。除非配置了allowCoreThreadTimeOut=true,核心线程数的线程也将不再保证长期存活于线程池内,在空闲时间超过keepAliveTime后被销毁。

workQueue:阻塞队列,存放等待执行的任务,线程从workQueue中取任务,若无任务将阻塞等待。当线程池中线程数量达到corePoolSize后,就会把新任务放到该队列当中。JDK提供了四个可直接使用的队列实现,分别是:基于数组的有界队列ArrayBlockingQueue、基于链表的无界队列LinkedBlockingQueue、只有一个元素的同步队列SynchronousQueue、优先级队列PriorityBlockingQueue。在实际使用时一定要设置队列长度。

maximumPoolSize(int):线程池内的最大线程数量,线程池内维护的线程不得超过该数量,大于核心线程数量小于最大线程数量的线程将在空闲时间超过keepAliveTime后被销毁。当阻塞队列存满后,将会创建新线程执行任务,线程的数量不会大于maximumPoolSize。

keepAliveTime(long):线程存活时间,若线程数超过了corePoolSize,线程闲置时间超过了存活时间,该线程将被销毁。除非配置了allowCoreThreadTimeOut=true,核心线程数的线程也将不再保证长期存活于线程池内,在空闲时间超过keepAliveTime后被销毁。

TimeUnit unit:线程存活时间的单位,例如TimeUnit.SECONDS表示秒。

RejectedExecutionHandler:拒绝策略,当任务队列存满并且线程池个数达到maximunPoolSize后采取的策略。ThreadPoolExecutor中提供了四种拒绝策略,分别是:抛RejectedExecutionException异常的AbortPolicy(如果不指定的默认策略)、使用调用者所在线程来运行任务CallerRunsPolicy、丢弃一个等待执行的任务,然后尝试执行当前任务DiscardOldestPolicy、不动声色的丢弃并且不抛异常DiscardPolicy。项目中如果为了更多的用户体验,可以自定义拒绝策略。

threadFactory:创建线程的工厂,虽说JDK提供了线程工厂的默认实现DefaultThreadFactory,但还是建议自定义实现最好,这样可以自定义线程创建的过程,例如线程分组、自定义线程名称等。

一般我们使用类的构造方法创建它的对象,ThreadPoolExecutor提供了四个构造方法。

线程池架构原理图解,线程池工作原理及方法(3)

可以看到前三个方法最终都调用了最后一个、参数列表最长的那个方法,在这个方法中给七个属性赋值。创建线程池对象,强烈建议通过使用ThreadPoolExecutor的构造方法创建,不要使用Executors,至于建议的理由上文中也有说过,这里再引用阿里《Java开发手册》中的一段描述。

线程池架构原理图解,线程池工作原理及方法(4)

栏目热文

线程池的原理及底层实现(线程池的结构和原理)

线程池的原理及底层实现(线程池的结构和原理)

作者:指尖上的榴莲www.jianshu.com/p/704a6c5d337c一.概述线程池,顾名思义就是存放线程的池子...

2022-11-03 05:47:00查看全文 >>

线程池实现的四种方式(线程池的四种状态)

线程池实现的四种方式(线程池的四种状态)

线程池的创建方式有四种,分别为手动创建,动态创建和自动生成。手动创建:创建方法有两种:(1)通过new来新建一个线...

2022-11-03 05:56:05查看全文 >>

线程池的七个参数(线程池各个参数含义)

线程池的七个参数(线程池各个参数含义)

所谓的线程池的 7 大参数是指,在使用 ThreadPoolExecutor 创建线程池时所设置的 7 个参数,如以下源...

2022-11-03 05:30:06查看全文 >>

高并发三种解决方法(大数据高并发解决方案)

高并发三种解决方法(大数据高并发解决方案)

一、什么是高并发高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通...

2022-11-03 06:02:03查看全文 >>

线程池的工作原理及图解(线程池源码深度解析)

线程池的工作原理及图解(线程池源码深度解析)

前言本文以程序员做需求的例子,比喻线程池的工作过程。以故事白话的方式展开,跟大家阐述线程池工作原理,以方便大家更好理解线...

2022-11-03 05:41:56查看全文 >>

线程池的使用实例(线程池的使用场景)

线程池的使用实例(线程池的使用场景)

线程池做什么: 网络请求通常有两种形式:第一种,请求不是很频繁,而且每次连接后会保持相当一段时间来读数据或者写数据,最后...

2022-11-03 05:37:09查看全文 >>

一张图看懂线程和进程(进程与线程通俗讲解)

一张图看懂线程和进程(进程与线程通俗讲解)

进程我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管...

2022-11-03 05:49:08查看全文 >>

线程池的四种实现方式(线程池创建的几种方法)

线程池的四种实现方式(线程池创建的几种方法)

不经常使用线程池的童鞋,还有对几种线程的使用不甚了解的童鞋,可以读一下此文,并关注后续线程池相关文章连载。本篇内容大纲:...

2022-11-03 05:36:42查看全文 >>

mycat和sharding优缺点(mycat的替代品)

mycat和sharding优缺点(mycat的替代品)

在我们的项目发展到一定阶段之后,随着数据量的增大,分库分表就变成了一件非常自然的事情。常见的分库分表方式有两种:客户端模...

2022-11-03 05:56:38查看全文 >>

线程池原理和实例(线程池的结构和原理)

线程池原理和实例(线程池的结构和原理)

前言线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配、调...

2022-11-03 06:03:39查看全文 >>

文档排行