Executors ThreaPoolExecutor创建线程池的区别

用法讲解

Executors

创建线程池有多种方式,列举最重要的三种如下:

 

//创建一个包含指定数目线程的线程池,如果任务数量多于线程数量,那么没有执行的任务必须等待,直到有任务完成为止。
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
//创建单一线程池 此方法可以创建单一线程池,线程池里只有一个线程,单一线程池可以实现以队列的方式来执行任务
private static ExecutorService threadPool1 = Executors.newSingleThreadExecutor();
//创建的是无界线程池,可以进行线程自动回收,此类线程池中存放线程个数理论值为Integer.MAX_VALUE最大值
private static ExecutorService threadPool2 = Executors.newCachedThreadPool();

说明弊端

Executors 各个方法的弊端:

1)newFixedThreadPool 和 newSingleThreadExecutor:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至 OOM。
2)newCachedThreadPool 和 newScheduledThreadPool:
主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。

ThreaPoolExecutor

创建线程池方式只有一种,就是走它的构造函数,参数自己指定:

常用构造函数如下:

参数讲解

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

corePoolSize - 线程池核心池的大小。
maximumPoolSize - 线程池的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 的时间单位。
workQueue - 用来储存等待执行任务的队列。
threadFactory - 线程工厂。

handler - 拒绝策略。

更为详细的介绍查看:点击打开链接

 

关注点1 线程池大小

线程池有两个线程数的设置,一个为核心池线程数,一个为最大线程数。
在创建了线程池后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法
当创建的线程数等于 corePoolSize 时,会加入设置的阻塞队列。当队列满时,会创建线程执行任务直到线程池中的数量等于maximumPoolSize。

关注点2 适当的阻塞队列

java.lang.IllegalStateException: Queue full
方法 抛出异常 返回特殊值 一直阻塞 超时退出
插入方法 add(e) offer(e) put(e) offer(e,time,unit)
移除方法 remove() poll() take() poll(time,unit)
检查方法 element() peek() 不可用 不可用

ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue: 一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue: 一个不存储元素的阻塞队列。
LinkedTransferQueue: 一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque: 一个由链表结构组成的双向阻塞队列。

关注点3 明确拒绝策略

ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。 (默认)
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

线程池创建选择

最近一段时间,个人用上了阿里巴巴的代码校验助手,会提示代码优化,然后本人用Executors创建线程池,被警告了,建议用手动创建线程池的方式,理由很简单:明晰线程池的创建,优化资源的利用。于是就去了解了一下两个的区别。

区别总结:Executors只提供三种常用的创建方式,但是资源配置的参数都是默认的,有时候,我们的线程池配置可能可以有更优的配置,那么Executors就满足不了了,所以Executors不适合定制化线程池。这个时候,我们就要选择ThreadPoolExecutor,

ThreadPoolExecutor实现Executors常用的三种方法

方法1:

Executors.newFixedThreadPool(nThreads);

源码1:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

模拟1:

private static ExecutorService t = new ThreadPoolExecutor(2, 2,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());

方法2:

Executors.newSingleThreadExecutor();

源码2:

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

模拟2:

new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())

方法3:

Executors.newCachedThreadPool()

源码3:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

模拟3:

new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>())

所以Executors实现的三种方法的源码其实是基于ThreadPoolExecutor封装的的。

所以,如果我们自己基于ThreadPoolExecutor去实现线程池,合理的配置各个参数,就可以创建出最合理的线程池。

spring框架实现的线程池配置

(ThreadPoolTaskExecutor在jar:org.springframework:spring-context)

<!-- spring thread pool executor -->
    <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 线程池维护线程的最少数量 -->
        <property name="corePoolSize" value="10"/>
        <!-- 允许的空闲时间 -->
        <property name="keepAliveSeconds" value="60"/>
        <!-- 线程池维护线程的最大数量 -->
        <property name="maxPoolSize" value="10"/>
        <!-- 缓存队列 -->
        <property name="queueCapacity" value="10"/>
        <!-- 对拒绝task的处理策略 -->
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
        </property>
    </bean>

理解还比较浅,请博友多多指教
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独行侠_阿涛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值