一, 3 个创建线程池的方法
- Executors.newSingleThreadExecutor(); // 单个线程的线程池
- Executors.newFixedThreadPool(5); // 固定大小的线程池
- Executors.newCachedThreadPool(); // 可伸缩的线程池, 遇强则强, 遇弱则弱
在阿里开发手册中:
线程池不允许使用 Executors 去创建, 而是通过 ThreadPoolExecutor 的方式, 这样的处理方式让写的同学更加明确线程池的运行规则, 规避资源耗尽的风险. 说明: Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE, 可能会堆积大量的请求, 从而导致 OOM.
2) CachedThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程, 从而导致 OOM.
以下为三种创建方法的函数的源码:
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService
- (new ThreadPoolExecutor(1, 1,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>()));
- }
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
- }
以下就是 ThreadPoolExecutor 函数, 有 7 大参数, 下节详细阐述.
二, 线程池的 7 大参数
(1) corePoolSize: 核心线程数 (当等待队列不满的时候, 只会调用核心线程)
(2) maximumPoolSize: 最大线程数 (当等待队列满了的时候, 会激活更多的线程)
(3) keepAliveTime: 新激活的线程在没有任务的情况下的存活时间
(4) TimeUnit:keepAliveTime 的单位
(5) BlockingQueue: 阻塞队列, 当核心线程满了, 新的请求会在队列中等待
(6) ThreadFactory: 创建线程的工厂, 使用默认的 Executors.defaultThreadFactory() 即可
(7) RejectedExecutionHandler: 拒绝策略, 当超出线程池的最大承载时的拒绝策略 (有 4 种拒绝策略)
现在我们再来看看阿里开发手册中的两句话:
1) FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE, 可能会堆积大量的请求, 从而导致 OOM.
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService
- (new ThreadPoolExecutor(1, 1,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>()));
- }
newSingleThreadExecutor 中的传入的阻塞队列参数为 new LinkedBlockingQueue<Runnable>() , 而 LinkedBlockingQueue 的默认构造函数的队列长度为 Integer.MAX_VALUE 约等于 21 亿, 所以可能会堆积大量的请求, 从而导致 OOM.FixedThreadPool 同理.
2) CachedThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程, 从而导致 OOM.
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
- }
newCachedThreadPool 中的传入的最大线程数参数为 Integer.MAX_VALUE, 可能会创建大量的线程, 从而导致 OOM.
那么最大线程数应该如何定义呢? 分以下两种情况:
CPU 密集型: 几个核心就定义为几, 可以保证 CPU 的效率最高, 例如一个 4 核的 CPU, 则可以令 maximumPoolSize = 4, 其中可以使用
Runtime.getRuntime().availableProcessors()
获取 CPU 的核数.
IO 密集型: 程序中有很多大型任务, IO 十分占用资源! 此时要判断程序中十分消耗 IO 的线程数, 只要大于该数即可, 一般可以设置为两倍.
三, 4 种拒绝策略
(1) ThreadPoolExecutor.AbortPolicy(): 当达到线程池的最大承载时, 还有请求, 则不处理, 并且抛出异常.
(2) ThreadPoolExecutor.CallerRunsPolicy(): 当达到线程池的最大承载时, 还有请求, 那条线程请求那条线程去处理, 一般为 main 线程.
(3) ThreadPoolExecutor.DiscardPolicy(): 当达到线程池的最大承载时, 还有请求, 则丢掉任务, 并且不抛出异常.
(4) ThreadPoolExecutor.DiscardOldestPolicy(): 当达到线程池的最大承载时, 还有请求, 则尝试去和最老的线程竞争, 并且不抛出异常.
来源: http://www.bubuko.com/infodetail-3717120.html