Executor框架(一) — 综述

一、概述

JDK中提供了Executor框架,便于我们进行多线程操作。

关联文章:

  1. Executor框架(二) — 线程池原理浅析
  2. Executor框架(三) — 几种常见的线程池
  3. Executor框架(四) — ThreadPoolExecutor源码解析

二、Executor 框架的两层调度模型

在这里插入图片描述
说明:
从图中可以看出,Java中执行异步任务采用两级调度模型来完成。
在上层,应用程序通过Executor框架控制上层的调度;
在下层,调度由操作系统内核控制,下层的调度不受应用程序的控制。


二、Executor 框架的类图

这里写图片描述
上图是 Executor框架 提供的功能。

Executor接口: 它是Executor框架的基础,它将任务的提交与任务的执行分离开来,无返回值;
ExecutorService接口: 提供了 submit(Runnable)、submit(Callable) 两个方法,带返回值;
AbstractExecutorService: 提供了两个转换方法,对 submit() 传递的参数进行包装;
ThreadPoolExecutor: 线程池的核心类,根据参数设置的不同,可以创建出多种类型的线程池;
ScheduledExecutorService接口: 由于 ThreadPoolExecutor 执行的任务都是实时的,不具备延迟功能,因此扩展了ExecutorService接口,提供了执行任务的功能;
ScheduledThreadPoolExecutor: ScheduledExecutorService接口的具体实现类;
Executors: 一个 Executor工厂类,提供了 FixedThreadPoolSingleThreadExecutorCachedThreadPoolScheduledThreadPoolExecutor 等类型的线程池;


三、Executor 框架包含的成员

在这里插入图片描述
在这里插入图片描述
Executor框架主要由3大部分组成。

  1. 任务。 包括被执行任务需要实现的接口:Runnable接口 或 Callable接口。

  2. 任务的执行。 包括任务执行机制的核心接口 Executor,以及继承自Executor的 ExecutorService 接口。

    Executor框架提供了两个实现了ExecutorService接口的实现类:ThreadPoolExecutorScheduledThreadPoolExecutor

  3. 异步计算的结果。 包括接口 Future 和实现Future接口的 FutureTask 类。

四、小结

  1. 提交任务到线程池的方式有两种:execute()submit()

    1. execute():不带返回值;
    2. submit():带返回值 Future
  2. 提交到线程池的 task 有两种类型: RunnableCallable

    1. Runnable:不带返回值的 task,execute(Runnable)submit(Runnable)
    2. Callable:带返回值的 task, submit(Callable)
  3. 线程池只能执行 Runnable 类型的 task,这个可以由 Executor.execute(Runnable) 看出;

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        //RunnableFuture接口实现了Runnable和Future接口
        RunnableFuture<Void> ftask = newTaskFor(task, null); 
        execute(ftask); //submit(Runnable)方法最终还是调用execute(Runnable)
        return ftask;
    }
    
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);  //submit(Callable)方法最终还是调用execute(Runnable)
        return ftask;
    }
    
  4. RunnableFutureFutureTask 的介绍。

    1. RunnableFuture 接口:继承了 Runnable 接口Future 接口
    2. FutureTask 类:实现了 RunnableFuture 接口
      FutureTask 内部只保存 Callable 类型的变量,但是FutureTask构造接收 RunnableCallable 两种类型的参数。因此,当接收到 Runnable 类型的参数时,需要调用 Executors.callable(runnable, result) 方法进行转换 。
    // RunnableFuture.class
    // 具备了提交给线程池执行的能力(Runnable),也具备取出返回值的能力(Future)
    public interface RunnableFuture<V> extends Runnable, Future<V> {
    	    void run();
    }
    // FutureTask.class
    public FutureTask(Callable<V> callable) {
    	if (callable == null)
    		throw new NullPointerException();
    	this.callable = callable;
    	this.state = NEW;   // ensure visibility of callable
    }
    // FutureTask.class
    public FutureTask(Runnable runnable, V result) {
    	//由于FutureTask只接收Callable,所以这里需要做一下转换。
        this.callable = Executors.callable(runnable, result); 
        this.state = NEW;  // ensure visibility of callable
    }
    // Executor.class
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result); //RunnableAdapter实现了Callable接口。
    }
    
  5. 由第1点、第2点和第3点可以得出以下结论:

    1. 如果是由 execute(Runnable) 提交的 task(Runnable类型),则线程池可以直接执行。
    2. 如果是由 submit(Runnable) 提交的 task(Runnable类型),由于需要返回一个 Future 对象接收数据,因此线程池不能直接执行 task,需要对 Runnable类型的 task 进行包装 。可以参考第4点。
    // AbstractExecutorService.class
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null); //RunnableFuture接口实现了Runnable和Future接口
        execute(ftask); //submit(Runnable)方法最终还是调用execute(Runnable)
        return ftask; //返回的RunnableFuture实现了Future接口
    }
    // AbstractExecutorService.class
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value); //可以参考第4点
    }
    
    1. 如果是由 submit(Callable) 提交的 task(Callable类型),由于线程池只能执行 Runnable 类型的 task,且需要返回一个 Future 对象接收数据,因此线程池不能直接执行 task,需要对 Callable 类型的 task 进行包装 。//可以参考第4点。
    // AbstractExecutorService.class
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task); //RunnableFuture接口实现了Runnable和Future接口
        execute(ftask);  //submit(Callable)方法最终还是调用execute(Runnable)
        return ftask; //返回的RunnableFuture实现了Future接口
    }
    // AbstractExecutorService.class
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable); //可以参考第4点
    }
    
  6. 通过返回的 Future 进行取值。由 submit() 提交任务后会返回一个 Future ,所以我们可以通过 Future.get() 取值(线程阻塞)。

发布了158 篇原创文章 · 获赞 26 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Love667767/article/details/52863406