1、线程池状态含义
ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量,之所以将信息存储在一个变量中,是为了保证原子性。
具体的高三位与线程池状态如下,引用自网课的图片:
2、构造方法的参数、具体工作方式
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
对于以上变量,其含义如下:
corePoolSize 核心线程数目 (最多保留的线程数)maximumPoolSize 最大线程数目
keepAliveTime 生存时间
unit 生存时间的时间单位
workQueue 阻塞队列
threadFactory 线程工厂 - 可以为线程创建时起个好名字
handler 拒绝策略
具体解释:
1.核心线程数:是指在线程池中始终保持存活的线程数量。在线程池中,当有新的任务到达时,线程池会创建新的线程来处理任务,但是当任务处理完毕后,线程并不会立即销毁,而是被放置在线程池中等待下一个任务的到来。
当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收,像这样:
executor.allowCoreThreadTimeOut(true); // 允许回收核心线程
2.最大线程数目:指核心线程数+非核心线程数的总数。例如设置核心为5,最大为10,那么非核心(救急)则为10-5=5个
3.生存时间:线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
4.阻塞队列:如果核心线程都被占用没有空闲,此时又多来了新任务,则新来的任务会被加入阻塞队列阻塞等待。
5.拒绝策略:如果阻塞队列满了,继续来任务,那么就创建救急线程来执行新任务,但如果救急线程也不够(达到最大线程数),再来任务,因为线程池已经填满了到极限了,所以就要拒绝新来的任务了。jdk和各种框架有多种拒绝策略的实现:
- AbortPolicy 让调用者抛出 RejectedExecutionException 异常,这是默认策略
- CallerRunsPolicy 让调用者运行任务
- DiscardPolicy 放弃本次任务
- DiscardOldestPolicy 放弃队列中最早的任务,本任务取而代之
- ActiveMQ 的实现,带超时等待(60s)尝试放入队列(较好)
3、 线程池有哪些常用的实现方式
3.1 newFixedThreadPool(全是、多个核心线程不回收)
fixed,即“固定的”,线程数固定,能够控制线程的最大并发数:
(1)源码中,其核心线程数和最大线程数都是nThreads,即相等,说明没有非核心线程
(2)阻塞队列是无界的,可以放任意数量的任务。
(3)核心线程不会自动回收,直到被明确打断:“The threads in the pool will exist until it is explicitly shutdown.”
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
//具体使用示例
//1.创建定长线程池对象,线程数量固定为3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//2. 创建Runnable线程对象以及执行的任务
Runnable task =new Runnable(){
public void run() {
System.out.println("执行任务啦");
}
};
//3. 向线程池提交任务
fixedThreadPool.execute(task);
3.2 newCachedThreadPool(全是非核心,定时回收)
Cached,缓存,是说这种线程池的实现像缓存一样是可变的:
(1)核心线程数是 0, 最大线程数是 Integer.MAX_VALUE,线程的空闲生存时间是 60s,意味着:这种线程池内都是非核心线程、可以无限创建、定时60s回收。
(2)队列采用了 SynchronousQueue ,特点是,它没有容量,没有线程来取是放不进去的。
(3)适合场景:执行大量、耗时少的任务。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
3.3 newSingleThreadExecutor(就一个核心线程,不回收)
Single,即单线程的线程池:只有 1 个核心线程,无非核心线程,执行后不会立即回收。
这样相当于顺序执行,不需要处理线程同步问题。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
3.4 newScheduledThreadPool(核心非核心都有,非核心定时回收)
Scheduled即定时的:核心线程数量固定,非核心线程数量无限多但会定时回收,当非核心线程执行完闲置 10ms 后则回收,任务队列为延时阻塞队列。
应用场景:执行定时或周期性的任务。
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;