“线程池”一点都不难嘛!
大家早上好呀,气温越来越高了,大家的学习耐心也很浮躁,小慕也能理解,不过该学习的地方还是得学,不然你拿什么还你房贷车贷?拿什么娶老婆,对吧?赶紧学习
今天小慕给大家分享的内容是有关线程池的入门知识,先对线程池有个大致的了解,知道怎么个回事就行。
在一个应用程序中,如果我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在Java中,内存资源是极其宝贵的,所以,我们就提出了线程池的概念,说白了,线程池的核心就是“线程重用”, 类似的池化技术应用还有数据库连接池、Redis连接池、http连接池、内存池等等。
一、啥是线程池?
线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
工作流程图如下所示
二、线程池的优点
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。
二、线程池的创建方式
public ThreadPoolExecutor( int corePoolSize, //核心线程的数量
int maximumPoolSize, //最大线程数量
long keepAliveTime, //超出核心线程数量以外的线程空余存活时间
TimeUnit unit, //存活时间的单位
BlockingQueue<Runnable> workQueue, //保存待执行任务的队列
ThreadFactory threadFactory, //创建新线程使用的工厂
RejectedExecutionHandler handler // 当任务无法执行时的处理器
) {...}
接下来我会详细针对各个参数进行细致的说明:
corePoolSize:线程池核心线程量
核心线程会一直存活,即使没有任务需要执行。当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理。设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭。如果调用了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程。
maximumPoolSize:线程池最大线程数
当线程数大于等于corePoolSize,且任务队列已满时,线程池会创建新线程来处理任务。当线程数等于maxPoolSize,且任务队列已满时,线程池根据设置的饱和策略来处理新任务。
keepAliverTime:非核心线程存活时间
当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间,当线程空闲时间达到keepAliveTime时,线程会逐渐消亡,直到线程数量等于corePoolSize为止。如果allowCoreThreadTimeout=true,则线程会逐渐消亡,直到线程数量等于0为止。
unit:存活时间的单位
workQueue:存放任务的队列
用来存储等待执行的任务,决定了线程池的排队策略,可以选择以下几个阻塞队列:
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。
SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 LinkedBlockingQueue。
PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
threadFactory:线程工厂
线程工厂可以用来定制一个线程,可以设置线程的优先级、名字、是否后台线程、状态等。
handler:饱和策略
当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。在JDK 1.5中Java线程池框架提供了以下4种策略。
AbortPolicy:直接抛出异常。
CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
DiscardPolicy:不处理,丢弃掉。
DiscardOldestPolicy:把队列里待最久的那个任务扔了,然后重新提交被拒绝的任务
四、线程池的大小设置为多少比较合适?
CPU密集型任务(N+1):这种任务消耗的主要是CPU资源,可以将线程数设置为N(CPU核心数)+1,比CPU核心数多出来一个线程是为了防止线程偶发的缺页中断,或者其他原因导致的任务暂停而带来的影响。一旦任务停止,CPU就会处于空闲状态,而这种情况下多出来一个线程就可以充分利用CPU的空闲时间。
I/O密集型(2N):这种任务应用起来,系统大部分时间用来处理I/O交互,而线程在处理I/O的是时间段内不会占用CPU来处理,这时就可以将CPU交出给其他线程使用。因此在I/O密集型任务的应用中,可以配置多一些线程,比如设置成2N。
好啦,今天的内容到这里就结束了,行百里者半九十,请不要半途而废,好吗?
点击蓝字