乐趣区

初读Java并发编程的艺术第十章Executor框架-101-Executor框架简介

在 java 中,直接使用线程来异步的执行任务,线程的每次创建与销毁需要一定的计算机资源开销。每个任务创建一个线程的话,当任务数量多的时候,则对应的创建销毁开销会消耗大量的资源,这种策略最终可能会使处于高负荷状态的应用崩溃。

Java 中的线程,即使工作单元,也是执行机制。从 JDK5 开始,把工作单元与执行机制分离开来。

  • 工作单元:Runnable 和 Callable
  • 执行机制:Executor 框架

1. Executor 框架简介

1.1 Executor 框架的两级调度模型

  • 在 HotSpot VM 的线程模型中,Java 线程(java.lang.Thread) 被一对一的映射为本地操作系统的线程。Java 线程的启动与销毁都与本地线程同步。操作系统会调度所有线程并将它们分配给可用的 CPU。
  • 在上层,Java 使用多线程的程序,通常会将应用分解为若干任务,然后使用用户级别的调度器(Executor 框架)将这些任务映射为对应数量的线程;
  • 底层,操作系统会将这些线程映射到硬件处理器上,切下层硬件的调度并不受应用程序的控制。调度模型如下图

1.2 Executor 框架的结构与成员

1. Excutor 框架的结构 - 主要由 3 大部分组成

  • 任务

    • Runnable 接口(无返回值)
    • Callable<V> 接口(有返回值)
  • 任务的执行
    执行机制的核心接口 -Executor,以及实现 Executor 接口的 ExecutorService,
    Executor 框架 中有两个关键类实现了 ExecutorService:

    • ThreadPoolExecutor

      线程池的实践类,执行被提交的线程、任务 (Callable/Runnable 接口的实现类中的 run() 方法)
    • ScheduledThreadPoolExecutor

      给定延迟或定期的执行任务 (Callable/Runnable 接口的实现类中的 run() 方法)、命令。比 Timer 更加灵活,强大。
  • 异步执行的结果(返回值)

    • Future 接口 可以通过 get()方法或者异步执行的结果
    • FutureTask<V> 类(实现了 Future 接口)

Executor 框架的使用:

  • 主线程(main 线程)创建实现 Runnable 或者 Callable<V> 接口的待执行任务对象。
  • Executors 可以将 Runnable 封装为 Callable<V> {Executors.callable(Runnable task)/(Runnable task,result)}。
  • Runnable 接口对象可以交由 ExexutorService 执行 {ExecutorService.executor(Runnable r) {无返回值};或者把 Runnable 接口对象或 Callable<V> 接口对象交由 ExecutorService 执行 {ExecutorService.submit(Runnable r/Callable<V> t) 有返回值 Futrue 接口的对象,现阶段 JDK 返回的是 FutureTask};
  • 最后,主线程(main 线程)执行 FutrueTask.get()阻塞,等待任务执行完成,同时获取返回值。也可以执行 FutureTask.cancel(boolean mayInterruptIfRunning)取消执行(参数表示如果正在执行是否取消)。

2. Executor 框架的成员

主要成员:ThreadPoolExecutor(线程池)、ScheduldThreadPoolExecutor、Runnable 接口、Future<V> 接口、Callable<V> 接口 以及 Executors 工具类。

  1. ThreadPoolExecutor
    通常使用 Executors 创建,Executors 可以创建三种类型的 ThreadPoolExecutor:SingleThreadExecuto、FixedThreadPool、CachedThreadPool

    • FixedThreadPool 创建固定线程数,适用于限制当前线程数量时,适用于负载较重的服务器。
      Executor 创建使用的 API:

      public static ExecutorService newFixedThreadPool(int nThreads);
      public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
    • SingleThreadExecutor 创建单个线程,任意时间点不会有多个线程是活动的,适用于需要保证顺序执行各任务的时候。
      Executors 创建 API:

      public static ExecutorService newSingleThreadPool();
      public static ExecutorService newSingleThreadPool(ThreadFactory threadFactory);
    • CachedThreadPool 根据需要创建新线程,大小无界的线程池,适用于执行大量短期的异步任务时,或负载较轻的服务器。

          Executors 创建 API
        ```java
        public static ExecutorService newCachedThreadPool();
        public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
        ```
  2. ScheduledThreadPoolExecutor
    使用 Executors 工厂类创建,Executors 可以创建两种类型的 ScheduldThreadPoolExecutor

    • ScheduledThreadPoolExecutor 包含若干个线程,适用于多个线程执行周期任务,同时限制执行的线程数量。
      Executors 创建固定个数线程 ScheduledThreadPoolExecutor 的 API:

      public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
      public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);
    • SingleThreadScheduledExecutor 之包含一个线程,适用于单个后台线程执行定时任务,同时保证顺序执行各个任务。
      Executors 创建单个线程 SingleScheduledExecutor 的 API:

      public static ScheduledExecutorService newSingleScheduledExecutor(int corePoolSize);
      public static ScheduledExecutorService newSingleScheduledExecutor(int corePoolSize, ThreadFactory threadFactory);
  3. Future 接口
    与其实现类 FutureTask 用于表示异步计算的结果。Runnable/Callable 接口提交(submit)给 ThreadPoolExecutor 或者 ScheduledThreadPoolExecutor 时候,返回值为 FutureTask 对象、实现类 Future 接口的对象。

    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
  4. Runnable 和 Callable 接口
    都可以被线程池执行,Runnable 无返回值,Callable 有返回值。
    Runnable 可以使用工厂类 Executors 将其封装为 Callble
    Executors 对应 API 如下:

    // 将返回的 Callable 对象提交给线程池返回 FutureTask 对象,调用 FutureTask.get(),返回 null
    public static Callable<Object> callable(Runnable task);
    
    // 同上提交,FutureTask.get(),返回 result 对象。public static Callable<Object> callable(Runnable task, T result);
        
退出移动版