线程池
作者:互联网
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
为解决此问题,我们需要使用线程池。
java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,下面主要来围绕这个类对线程池进行介绍。
线程池的创建
7个核心参数+4种丢弃策略
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize: 表示常驻核心线程数。如果等于0,则执行完任务之后,没有任何请求进入时销毁线程池的线程;如果大于0,即使本地任务执行完,核心线程也不会被销毁。这个值非常关键,设置过大会浪费资源,过小会导致线程频繁的创建或销毁。
maximumPoolSize: 表示线程池能够同时执行的最大线程数,这个值必须大于1,如果执行的线程数大于此值,则需要借助第5个参数的帮助,缓存在队列中。如果maximumPoolSize与corePoolSize相等,即是固定大小的线程池。
keepAliveTime: 表示线程池中的线程空闲时间,当空闲时间达到keepAliveTime值时,线程会被销毁,直至剩下corePoolSize个线程为止,避免浪费内存和句柄资源。在默认情况下,当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用。但是当ThreadPoolExecutor的allowCoreThreadTimeOut变量值设为true时,核心线程超时后也会被收回。
unit: 表示时间单位。keepAliveTime 的时间单位通常时TimeUnit.SECONDS.
workQueue: 表示缓存队列。当请求的线程数大于maximumPoolSize时,线程进入BlockingQueue阻塞队列。
threadFactory: 表示线程工厂。他用来生产一组相同任务的线程。线程池的命名是通过给这个factory增加组名前缀名来实现的。在虚拟机栈分析时就可以知道线程任务是有哪个线程工厂来产生的。
handler: 表示执行拒绝策略的对象。当超过第5个参数workQueue的任务缓存区上限时,就可以通过该策略处理对象,这是一种简单的限流保护。
拒绝策略主要包含:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
由这些参数可知,线程池的工作过程如下:
1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面 有任务,线程池也不会马上执行它们。
2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:
a) 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b) 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
c) 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要 创建非核心线程立刻运行这个任务;
d) 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池 会抛出异常 RejectExecutionException。
3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。
4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,
如果当前运 行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它 最终会收缩到 corePoolSize 的大小。
标签:corePoolSize,keepAliveTime,队列,任务,线程,ThreadPoolExecutor 来源: https://www.cnblogs.com/Hyacinth-Yuan/p/15680359.html