java线程池底层运行过程以及参数详解
1.Java线程池基本的创建
newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
2.线程在底层流转逻辑
在线程池中创建线程的时候首先会判断一下是否大于自己设定的线程核数如果大于然后进行队列中判断看看缓冲队列中是否已满,如果缓冲队列中满了判断是否大于最大线程数也就是我们申明的时候在方法中加的参数,如果大于则根据拒绝策略执行相应的操作.
如果在判断小于核心线程数 则执行创建线程,如果判断队列未满的时候则放入队列等待执行创建 如果判断小于最大线程数也执行创建任务
3.在源码中我们看到
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
其中ThreadPoolExecutor这个构造函数中
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
}
有7个参数这几个参数非常重要也是构成线程的核心
1、corePoolSize 【核心线程数】
核心线程数就是线程池实际的线程数量,且这些线程一旦开启后就不会轻易关闭,队列中的任务执行时优先使用空闲的核心线程,直到超过 keepAliveTime 时间后才会关闭;
2、 maximumPoolSize 【最大线程数】
线程池能 容纳的最大线程数量,当核心线程满了,并且队列也满了之后,在来新任务的话,就会使用最大线程数的空间来创建新线程;
3、 keepAliveTime 【空闲线程存活时间】
核心线程在执行完任务后不会立马关闭,而是直到超过 keepAliveTime 时间后才会关闭,如果把 keepAliveTime 为 0 ,那么执行完任务后会立马回收(这一点很多博主都写错了,说是设置为0将永不回收,其实是错误的)
4、unit 【空闲线程存活时间单位】
keepAliveTime 的时间单位,主要有以下几种:
TimeUnit.DAYS 天
TimeUnit.HOURS 小时
TimeUnit.MINUTES 分钟
TimeUnit.SECONDS 秒
TimeUnit.MILLISECONDS 毫秒
TimeUnit.MICROSECONDS 微秒
TimeUnit.NANOSECONDS 纳秒
5、 workQueue 【等待执行的任务队列】
当核心线程运行的任务数量已经满了之后,那么在添加进来的任务就进入 workQueue 队列中,待核心线程任务执行完后会依次执行队列中的任务;等待执行的队列遵循先进先出,后进后出的原则,就是先加进来的任务优先执行;默认任务队列使用的 ConcurrentLinkedQueue 队列,是一个无界的非阻塞队列;无界是没有界限的意思,大小不受限制,会自动扩容;就像动态数组一样;
6、 threadFactory 【创建新线程时使用的工厂】
创建新线程时使用的工厂类,默认使用 DefaultThreadFactory ,可自定义工厂,只需要继承 ThreadFactory 接口即可;可以用来设定线程名、是否为daemon(守护线程)等等 ,
7、 handler 【拒绝策略】
当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,拒绝策略需要实现 RejectedExecutionHandler 接口,jdk中提供了4种拒绝策略
CallerRunsPolicy 直接在主线程运行被拒绝的任务,除非线程池已关闭,已通过实验证实;我们看看源代码,r.run() 里面的 r 其实就是主线程
AbortPolicy 直接丢弃任务,并抛出RejectedExecutionException异常;
DiscardPolicy 直接丢弃任务,什么也不做,看源码就知道,里面啥也没有
DiscardOldestPolicy 抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列
当然除了jdk自带的策略外,你也可以通过实现 RejectedExecutionHandler 接口来自定义策略;