java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》
系统创建和销毁一个线程的成本是比较高的, 因为它涉及到与操作系统的交互. 因此, 使用线程池可以很好地提高性能, 尤其是在系统需要频繁创建大量且生命周期很短暂的线程时. 线程池和数据库连接池异曲同工.
1. 线程池创建工具类-Executors
在java5之前, 我们需要自己动手创建线程池, 设置初始化数量, 阻塞队列等. 从java5 之后, java 新增了Executors 工厂类来创建线程池, Executors 提供了一组静态方法来创建线程池, 更为便捷.
1.1 Executors API
- Executors 创建线程池的API 分为两组, 一种是使用默认的ThreadFactory, 一种使用自定义的ThreadFactory. 前者更为常用
- Executors 创建的线程池实现类有三种:
- ThreadPoolExecutor: 创建单线程池, 固定线程池, 缓存线程池
- ScheduledThreadPoolExecutor: 创建调度线程池
- ForkJoinPool: 创建工作窃取模式线程池
方法签名 | 方法描述 | 自动销毁空闲线程 | 底层实现类 |
---|---|---|---|
public static ExecutorService newSingleThreadExecutor() | 创建只有一个线程的线程池 | 不会 | ThreadPoolExecutor |
public static ExecutorService newFixedThreadPool(int nThreads) | 创建一个固定数量线程的线程池 | 不会 | ThreadPoolExecutor |
public static ExecutorService newCachedThreadPool() | 创建一个具有缓存功能的线程池, 线程数可无限递增 | 线程空闲60秒后, 会自动销毁 | ThreadPoolExecutor |
public static ScheduledExecutorService newSingleThreadScheduledExecutor() | 创建具有调度功能的单线程池, 可延迟执行线程任务 | 不会 | ScheduledThreadPoolExecutor |
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) | 创建具有指定线程数量的线程池, 拥有延迟调度功能. | 不会 | ScheduledThreadPoolExecutor |
public static ExecutorService newWorkStealingPool() | 创建ForkJoinPool 线程池, 默认线程数量为当前cpu 的核数 | 不会 | ForkJoinPool |
public static ExecutorService newWorkStealingPool(int parallelism) | 创建ForJoinPool线程池, 指定线程数量 | 不会 | ForkJoinPool |
1.2 Executors 源码
/* 使用ThreadPoolExecutor 创建单线程池:
1) 初始化和最大线程数量设置为1
2) 线程空闲时间设置为0, 表示不自动销毁
3) 阻塞队列为LinkedBlockingQueue, 数量无上线
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
/* 使用ThreadPoolExecutor 创建单线程池:
1) 初始化和最大线程数量设置为固定值
2) 线程空闲时间设置为0, 表示不自动销毁
3) 阻塞队列为LinkedBlockingQueue, 数量无上线
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/* 使用ThreadPoolExecutor 创建单线程池:
1) 初始化线程设置为0, 表示线程池中默认为0个线程, 当需要池才进行创建
2) 最大线程数量设置为Integer.MAX_VALUE, 可理解为无上限
3) 线程空闲时间设置为60s, 表示线程空闲60 秒后, 自动销毁
4) 阻塞队列为同步队列(没有容量, 一个put,必须等待一个take), 不缓存任务, 有新的任务直接创建线程
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
// 使用ScheduledThreadPoolExecutor创建调度单线程池, 设置线程数量为1
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
// 使用ScheduledThreadPoolExecutor创建调度单线程池, 设置线程数量为固定值
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
// 利用工作窃取框架创建ForkJoinPool 线程池. 以当前服务器的处理器核数来设定线程数
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
// 利用工作窃取框架创建ForkJoinPool 线程池. 以固定值来设置当前处理器核数
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
2. 线程池接口-ExecutorService
2.1 ExecutorService API
- 线程任务提交后并不是立即执行, 而是当线程池有空闲线程时, 才开始执行
- 线程任务提交后会返回Future对象, 可通过FurtureAPI 查看线程任务执行状态, 取消执行等操作
- 注意invokeAny 和 invokeAll 有两点区别:
- invokeAll 提交的所有任务都会正常结束, 而invokeAny 在任一任务完成后, 便取消其它任务
- invokeAny 提交线程任务时会阻塞主线程, 而invokeAll 提交时, 不会阻塞主线程.
方法签名 | 方法描述 | 是否是阻塞API |
---|---|---|
Future<?> submit(Runnable task) | 否 | 执行Runnable类型的任务, 当线程池有空闲时间时才会执行. |
Future submit(Callable task) | 否 | 提交Callable类型的任务, 有返回值 |
Future submit(Runnable task, T result) | 否 | 提交Runnable 类型异步任务, 无返回值 |
List<Future> invokeAll(Collection<? extends Callable> tasks) | 是 | 批量提交Callable 线程任务 |
List<Future> invokeAll(Collection<? extends Callable> tasks, long timeout, TimeUnit unit) |
是 | 批量提交Callable线程任务, 并设置超时时间, 超时抛出异常 |
T invokeAny(Collection<? extends Callable> tasks) | 是 | 提交一组Callable线程任务, 只要其中一个执行结束, 则取消其它未执行完的任务 |
T invokeAny(Collection<? extends Callable> tasks, long timeout, TimeUnit unit) | 是 | 较上一个API 新增超时功能 |
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException | 是 | 阻塞等待线程池中所有任务执行结束, 可设置超时等待时间 |
boolean isShutdown() | 是 | 判断线程池是否关闭 |
void shutdown() | 是 | 关闭线程池, 如果有任务正则运行, 则等待任务运行结束后关闭线程池. 同时拒绝接收新的线程任务 |
List shutdownNow() | 是 | 强制结束线程池, 纵使有线程任务正则运行 |
2.2 ScheduledExecutorService API
- ScheduledExecutorService 基础ExecutorService, 拥有ExecutorService的相关方法, 但是我们通常只关注ScheduledExecutorService 调度相关的方法
- ScheduledExecutorService 的定时与延迟任务的执行, 前提都必须是线程池中有可用线程时.
- 对于重复调度的功能, 当有未捕获异常抛出时, 重复调度结束
方法签名 | 方法描述 |
---|---|
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) | 指定Runnable任务延迟delay之后执行, 无返回值 |
public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) | 指定Callable任务延迟delay之后执行, 有返回值 |
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) | 上次任务执行开始后, period时间后, 再次重复执行; 无论上次任务是否已经执行结束 |
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) | 上次任务执行结束后, 延迟delay时间, 进行重复执行 |