【JUC线程池】ExecutorService以及Executors线程池类型
JUC:java.util.concurrent是Java的并发包。我认为当我们了解关于Java的多线程,就应该知道线程池从何而来:是为了解决在多线程并发的环境下,对于减少线程的创建和释放内存和资源下所以才会有线程池的概念。所以第一步就要先了解如何创建线程池。
线程池创建
初次了解线程池肯定会了解到ThreadPoolExecutor类,其内部有四种有参构造方法均是为了创建线程池。接下来主要示范的是七个形参的构造方法。
/**
* int corePoolSize:核心线程数,必定大于0
* int maximumPoolSize:最大线程数,必定大于等于0并且大于等于核心线程数
* long keepAliveTime:空闲线程最大存活时间,必定大于0,时间到期就被释放
* TimeUnit unit:时间单位(用TimeUtil指定)
* BlockingQueue<Runnable> workQueue:任务队列,不为null
* ThreadFactory threadFactory:创建线程工厂,不为null,有默认值
* RejectedExecutionHandler handler:任务的拒绝策略,不为null,有默认值
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
}
corePoolSize:如果创建的线程数未达到指定的核心线程数,则会继续创建新的核心线程数达到指定值,而后创建的线程均不为核心线程,而是非核心线程。
maximnmPoolSize:如果最大线程数等于核心线程数,则无法创建非核心线程。如果非核心线程处于空闲时,超过设置的空闲时间就会被回收,释放占用的资源。
keepAliveTime:非核心线程的存活时间。
BlockingQueue<Runnable>:任务队列,指存放被提交但尚未被执行的任务的队列。
ThreadFactory(可无):线程工厂,用于创建线程,默认是Executors.defaultThreadFactory()。
RejectedExecutionHandler(可无):当线程边界和队列容量已经达到最大时用于处理阻塞的程序。默认是AbortPolicy:任务满了将其多余的任务丢掉且抛异常。
任务队列
直接提交型(SynchronousQueue)
(1)SynchronousQueue没有容量。
(2)提交的任务不会被真实的保存在队列中,而总是将新任务提交给线程执行。如果没有空闲的线程,则尝试创建新的线程。如果线程数大于最大值maximumPoolSize,则执行拒绝策略。
有界型(ArrayBlockingQueue)
(1)创建队列时,指定队列的最大容量。
(2)若有新的任务要执行,如果线程池中的线程数小于corePoolSize,则会优先创建新的线程。若大于corePoolSize,则会将新任务加入到等待队列中。
(3)若等待队列已满,无法加入。如果总线程数不大于线程数最大值maximumPoolSize,则创建新的线程执行任务。若大于maximumPoolSize,则执行拒绝策略。
无界型(LinkedBlockingQueue)
(1)与有界队列相比,除非系统资源耗尽,否则不存在任务入队失败的情况。
(2)若有新的任务要执行,如果线程池中的线程数小于corePoolSize,线程池会创建新的线程。若大于corePoolSize,此时又没有空闲的线程资源,则任务直接进入等待队列。
(3)当线程池中的线程数达到corePoolSize后,线程池不会创建新的线程。
(4)若任务创建和处理的速度差异很大,无界队列将保持快速增长,直到耗尽系统内存。
(5)使用无界队列将导致在所有 corePoolSize 线程都忙时,新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize(因此,maximumPoolSize 的值也就无效了)。当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
优先任务型(PriorityBlockingQueue)
(1)带有执行优先级的队列。是一个特殊的无界队列。
(2)ArrayBlockingQueue和LinkedBlockingQueue都是按照先进先出算法来处理任务。而PriorityBlockingQueue可根据任务自身的优先级顺序先后执行(总是确保高优先级的任务先执行)。
————————————————
版权声明:本文为CSDN博主「J_bean」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/j_bean/article/details/78612988
任务拒绝策略
AbortPolicy
DiscardPolicy
DiscardOldestPolicy
CallerRunsPolicy
ExecutorService
ExecutorService是Executor的子接口。是对线程池的实现。Executor接口中只有一个execute()方法,里面传递的是Runnable接口,就是相当于传入一个线程。而ExecutorService中就有几种方法是对线程的运用。注意:Executor与下文讲的Executors是不一样的。
shutdown():在完成已经提交的任务后销毁线程
shutdownNow():直接停止现在的任务并返回之前执行的任务后销毁线程
isShutdown():判断线程是否已经被销毁
isTerminated():判断所有任务是否执行完毕
submit(Runnable task):提交Callable或者Runnable任务
那么讲完了ExecutorService中对线程的方法操作,该如何去创建对应的线程池呢?
线程池类型
缓存型
通过Executors.newCachedThreadPool();创建。通过其源码可以发现:没有核心线程数,有很多的非核心线程数,存活时间是大约2分钟。由此可见适用于生命周期短的任务。
单线程型
通过Executors.newSingleThreadExecutor();创建。通过其源码可以发现:只有1个核心线程数并且最大线程数也为1,没有存活时间,用的是无界型任务队列,保证任务FIFO顺序执行。
固定线程型
通过Executors.newFixedThreadPool();创建。通过其源码可以发现:核心线程数等于最大线程数,非核心线程不存活,也就是相当于只执行传来参数的线程数量。
固定核心线程型
通过Executors.newScheduledThreadPool();创建。通过其源码可以发现:传入的参数就是核心线程数,非核心线程数很多且不存活。