09. 线程池-Executors 相关API

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时间, 进行重复执行
发布了321 篇原创文章 · 获赞 676 · 访问量 147万+

猜你喜欢

转载自blog.csdn.net/zongf0504/article/details/100186141