线程池执行原理

线程池参数设置

1.corePoolSize 核心线程数,默认是cpu核数。
2.maximumPoolSize 最大线程数,默认是Integer.MAX_VALUE。
3.keepAliveTime 非核心线程空闲时间,默认60s。
4.unit 时间单位,默认TimeUnit.SECONDS。
5.workQueue 阻塞队列,默认是LinkedBlockingQueue。
6.threadFactory 线程工厂,默认是DefaultThreadFactory。

执行原理

当我们提交任务时,要先判断核心线程是否已满,若没满则添加到工作线程并执行,若满了则判断阻塞队列是否已满,若没满则把任务添加到阻塞队列,若满了则判断线程数是否小于最大线程数,若小于则我们使用非核心线程来处理最新的任务,处理后非核心线程会检查阻塞队列中是否有要执行的线程,若有则处理。若线程数大于最大线程数,则使用拒绝策略。
拒绝策略分四点:
1.AbortPolicy:直接抛出异常,默认。
2.CallerRunsPolicy:由调用者所在的线程来执行任务。
3.DiscardOldestPolicy:丢弃阻塞队列中最靠前的任务,并执行当前任务。
4.DiscardPolicy:直接丢弃任务,不处理。
线程池执行原理

关于阻塞队列

阻塞队列一共有四个
1.ArrayBlockingQueue 基于数组的有界阻塞队列,FIFO
2.LinkedBlockingQueue 基于链表的阻塞队列,FIFO
3.PriorityBlockingQueue 优先级队列,保证执行的任务是队列中最靠前的
4.DelayQueue 不存储元素,插入新任务必须等上一个任务完成并移出。

ArrayBlockingQueue LinkedBlockingQueue
强制规定大小 不强制规定大小,规定也行
数组构成 链表构成
提前初始化Node数组 创建节点时添加数据
Node数组提前创建 数据入队生成新Node
一把锁 两把锁(头尾)

确定核心线程数

1 在高并发且任务执行时间短 -> cpu核数+1,减少上下文切换
2 并发不高但任务执行时间长
· IO密集型任务 -> cpu核数*2+1
· 计算密集型任务 -> cpu核数+1
3 并发高且任务执行时间长 -> 这类任务就不是设置线程池能够解决的了,首先尝试为数据作缓存,其次增加服务器。

线程池种类

1.FixedThreadPool 固定线程池,线程数量固定,任务按照提交顺序执行,超出的线程会在队列中等待。
2.SingleThreadExecutor 单线程线程池,只有一个线程,任务按照提交顺序执行。
3.CachedThreadPool 缓存线程池,没有核心线程,只有非核心线程,且线程数量不固定,空闲线程会被回收(能够存活60S),任务按照提交顺序执行。
4.ScheduledThreadPool 定时线程池,线程数量不固定,任务按照延迟时间执行。