线程池:
线程池提供了一种限制和管理资源(包括执行一个任务)。每个线程池还维护了一些基本统计信息。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。
使用线程池的好处:
- 降低资源消耗。(重复利用已创建的线程,降低了线程重复创建和销毁造成的消耗。)
- 提高响应速度(当任务到达时,不需要等到线程创建就能立即执行。)
- 提高线程的可管理性(无限制的创建线程,会消耗系统资源和降低系统的稳定性,使用线程池可以统一的分配,调优和监控)
线程池的创建
在《阿里巴巴Java开发手册中》规定不允许使用Executors工具类创建线程,而是通过ThreadPoolExecutor构造器创建,这样可以避免OOM的发生。
1、通过构造方法创建线程池
ThreadPoolExecutor类中提供了四个构造方法,其中三个都是在下面方法的基础上添加了一些默认参数。
/**
* Creates a new ThreadPoolExecutor with the given initial
* parameters.
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数分析(七大参数):
- corePoolSize:即使在空闲状态下也要保留在池中的线程数,除非设置了allowCoreThreadTimeOut
- maximumPoolSize:池中允许的最大线程数
- keepAliveTime:当池中线程数大于内核数(corePoolSize)时,keepAliveTime是多余的空闲线程将在终止之前等待新任务的最长时间。
- unit:keepAliveTime参数的时间单位
- workQueue:在执行任务之前用于保留任务的队列。该队列将仅保存由代码execute方法提交的Runnable任务。
- threadFactory:执行程序创建新线程时要使用的工厂
- handler:(饱和策略)因为达到了线程界限和队列容量而在执行被阻止时使用的处理程序
ThreadPoolExecutor饱和策略
如果当前同时运行的线程数量达到最大线程数量,并且队列也已经被放满任务时,ThreadPoolTaskExecutor定义了一些策略:
- ThreadPoolExecutor.AbortPolicy(默认):抛出
RejectedExecutionException
来拒绝新任务的处理 - ThreadPoolExecutor.CallerRunsPolicy:调用执行自己的线程运行任务。这种策略会减低新任务的提交速度,影响程序的整体性能。另外,这个策略喜欢增加队列容量。如果你的应用程序可以承受延迟并且你不能任意丢弃任何一个任务请求时,你可以选择这个策略。
- ThreadPoolExecutor.DiscardPolicy:不处理新任务,直接丢弃掉。
- ThreadPoolExecutor.DiscardOldestPolicy:此策略将丢弃最早的为处理的任务请求。
2、通过 工具类Executors 创建线程池的四种方法:
* 第一种:创建一个单线程的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
* 第二种:创建一个固定大小的线程池,参数为线程的数量;
ExecutorService executorService = Executors.newFixedThreadPool(2);
* 第三种:创建一个可缓存的线程池,该线程池可回收部分空闲(60秒不执行任务)的线程,
可自动增加线程.此线程池不会限制线程池的大小啊
ExecutorService executorService = Executors.newCachedThreadPool();
* 第四种:创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务.
ExecutorService executorService = Executors.newScheduledThreadPool(3);
缺点:
- 第一、二方法 ,线程池大小固定,允许请求的队列长度为Integer.MAX_VALUE,可能堆积大量请求,从而导致OOM。
- 第三、四方法,线