文章目录
Java 中提供Executor
框架用来帮助用户使用线程池
线程池的作用:
- 复用线程、控制最大并发数等
- 实现任务线程队列缓存策略和拒绝策略
- 实现某些与时间相关的功能,如定时执行、周期执行等
- 隔离线程环境
一、Executor
简介
如图:
通过Executor框架的根据类Executors,可以创建三种基本的线程池:
ForkJoinPool
ThreadPoolExecutor
ScheduledThreadPoolExecutor
核心方法如下:
(1)Executors.WorkStealingPool
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
JDK8 引入,创建持有足够线程的线程池支持给定的并行度,并通过使用多个队列减少竞争,此构造方法中把 CPU 数量设置为默认的并行度
(2)Executors.newCachedThreadPool
CachedThreadPool是一个会根据需要创建新线程的线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue());
SynchronousQueue
是一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然。
corePoolSize
是 0,maximumPoolSize
都最大,无界的。keepAliveTime
为60秒,空闲线程超过 60秒 会被终止。
适用场景:适用于短期异步的小任务,或负载教轻的服务器
(3)Executors.newScheduledThreadPool
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
//可以直接执行
executor.execute(new JobTaskR("executor", 0));
executor.execute(new JobTaskR("executor", 1));
System.out.println("5S后执行executor3");
//隔5秒后执行一次,但只会执行一次。
executor.schedule(new JobTaskR("executor", 3), 5, TimeUnit.SECONDS);
System.out.println("开始周期调度");
//设置周期执行,初始时6S后执行,之后每2s执行一次
executor.scheduleAtFixedRate(new JobTaskR("executor", 4), 6, 2, TimeUnit.SECONDS);
scheduleAtFixedRate
或者scheduleWithFixedDelay
方法,它们不同的是前者以固定频率执行,后者以相对固定延迟之后执行。
线程数最大至 Integer.MAX_VALUE
,存在 OOM
风向。
支持定时及周期性任务执行。
ScheduleThreadPoolExecutor
和Timer
类似,可以设置延时执行或周期执行,但比Timer
有更多的功能,ScheduledExecutorService
更安全,功能更强大。
Timer
和TimerTask
只创建一个线程,任务执行时间超过周期会产生一些问题。Timer创建的线程没有处理异常,因此一旦抛出非受检异常,会立刻终止。
与newCachedThreadPool
区别是不回收工作线程
(4)Executors.newSingleThreadPool
核心线程池数量
corePoolSize
和最大数量maximumPoolSize
都设置为1
适用于需要保证顺序执行的场景
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
适用场景:保证顺序执行
(5)Executors.newFixedThreadPool
可重用固定线程数的线程池
// 获取fixedThreadPool
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(paramInt);
// 内部会调用下面的方法,参数 corePoolSize、maximumPoolSize、keepAliveTime、workQueue
return new ThreadPoolExecutor(paramInt, paramInt, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
FixedTheadPool
设置的线程池大小和最大数量一样;keepAliveTime
为0,代表多余的空闲线程会立刻终止;保存任务的队列使用LinkedBlockingQueue
,当线程池中的线程执行完任务后,会循环反复从队列中获取任务来执行。
FixedThreadPool
适用于限制当前线程数量的应用场景,适用于负载比较重的服务器。
二、详细
方法图: