Java Runnable,Callable和FutureTask详解

目 录

[1 序言](#1 序言)

[2 基本概念](#2 基本概念)

[2.1 Runnable 和 Callable的区别](#2.1 Runnable 和 Callable的区别)

[2.2 Future 和 FutureTask](#2.2 Future 和 FutureTask)

[2.3 ExecutorService中Future的应用](#2.3 ExecutorService中Future的应用)

[2.4 Future submit(Runnable task)](#2.4 Future submit(Runnable task))

[2.5 Future submit(Callable task)](#2.5 Future submit(Callable task))

[2.6 ExecutorService中execute()在ThreadPoolExecutor中实现如下:](#2.6 ExecutorService中execute()在ThreadPoolExecutor中实现如下:)

[3 Future,RunnableFuture,FutureTask 关系](#3 Future,RunnableFuture,FutureTask 关系)

[4 总结](#4 总结)

参考文献


1 序言

本文针对多线程中使用的几种任务:Runnable、Callable、RunnableFuture,FutureTask等进行详细介绍

2 基本概念

2.1 Runnable 和 Callable的区别

Runnable和Callable都是定义了接口,可以用在线程池中异步执行,区别是:

  • Runnable可以直接被Thread执行,但是没有返回值
  • Callable执行之后有返回值,但是只能提交给线程池执行。

2.2 Future 和 FutureTask

Future是一个接口,主要是线程池中任务执行之后用于返回结果的获取,定义了

  • boolean cancel(boolean mayInterruptIfRunning); 取消任务
  • boolean isCancelled(); 任务是否取消
  • boolean isDone(); 任务是否执行完毕
  • V get(); 获取任务执行的结果,注意这个方法阻塞线程
  • V get(long timeout, TimeUnit unit); 同上,只是增加了一个超时时间

Future有一个直接继承接口RunnableFuture,RunnableFuture有一个实现的子类FutureTask,RunnableFuture这个接口同时还继承了Runnable接口,这意味着FutureTask可以作为Future或者Runnable使用。

再来看一下FutureTask的实现,最终内部保存了一个Callable对象,也就是提交的任务

先看构造函数

一共2个构造函数,一个是接受Callable,一个是接受Runnable和默认返回值。

详细看一下第二个构造参数,注释很清楚的说明,当你需要runnable可取消同时不关心返回值时,可以这样构建

上面两个函数将一个Runnable适配成了一个Callable,是Executors中提供的静态方法。

再看一下FutureTask对Runnable的实现

抛开其他的判断条件,其实就是对内部保存的Callable调用了call方法,进行执行并保存结果。这就是FutureTask主要的几个方法,下面有用。

2.3 ExecutorService中Future的应用

上面2点主要是为了给这点做伏笔,现在我们来看为什么ExecutorService中的submit()既可以提交Runnable又可以提交Callable并返回结果,同时看看直接execute() Runnable会有什么不同。

2.4 Future submit(Runnable task)

先来看一下这个方法的实现

代码上可以很直观的看到,提交的Runnable被newTaskFor()适配成了RunnableFuture。来看一下newTaskFor()这个方法的实现。

复制代码

直接是new了一个FutureTask对象,上面我们分析过这种情况,runnable其实是会被适配成一个Callable的。

2.5 Future submit(Callable task)

再来看一下这个方法

复制代码

跟上面的代码简直一摸一样,都是适配成了RunnableFuture。

看到这里可以明白,提交Runnable时是将Runnable适配成了Callable,也就是submit方法最终都会调用的的是Callable对象。

上面我们说过RunnableFuture实现了Runnable接口,当他被execute时,肯定是被当作Runnable使用的,看一下两个submit方法最终都是通过execute来执行的。

上面介绍FutureTask时我们知道,对Runnable的实现FutureTask最后调用的是Callable的call方法。

到这里可以知道了,

  1. 当我们提交一个Runnable的任务时,首先通过FutureTask的构造函数被适配成了一个Callable对象被保存FutureTask中。
  2. 当任务被执行时,FutureTask又被当作一个Runnable使用,调用了保存在内部的Callable的call方法,任务被执行并返回了结果。
  3. Runnable被适配成Callable时最终调用的还是自己的run方法。

2.6 ExecutorService中execute()在ThreadPoolExecutor中实现如下:

上面注释的意思是:

  1. 当前核心线程数少于corePoolSize是,尝试直接新建Thread用来执行任务。同时校验添加的过程,防止出错。
  2. 任务入队时二次校验是否需要新建线程,判断是否需要回滚等。
  3. 如果任务不能入队则新建非核心线程处理,如果失败那么就拒绝任务。

这个就是任务具体执行的过程

3 Future,RunnableFuture,FutureTask 关系

再来看构造方法,有两个构造方法如下

4 总结

主要讲了几个概念Runnable、Callable、Future,RunnableFuture,FutureTask 以及相关的子类,总结如下:

  • Runnable可以直接被Thread执行,但是没有返回值
  • Callable执行之后有返回值,但是只能提交给线程池执行。
  • Future定义了一系列关于任务管理的接口方法
  • FutureTask是Future唯一实现类,它也实现了Runnable接口
  • 线程池submit Callable和Runnable时最终都会转换成FutureTask
  • FutureTask被执行时是被当成Runnable使用的,执行了内部保存的Callable的call方法

参考文献

https://juejin.cn/post/6844903672736907272

https://blog.csdn.net/weixin_34244102/article/details/87973014

https://blog.csdn.net/sageyin/article/details/116035166

相关推荐
尘浮72811 分钟前
60天python训练计划----day45
开发语言·python
Magnum Lehar15 分钟前
vulkan游戏引擎test_manager实现
java·算法·游戏引擎
sss191s16 分钟前
校招 java 面试基础题目及解析
java·开发语言·面试
异常君20 分钟前
MySQL 中 count(*)、count(1)、count(字段)性能对比:一次彻底搞清楚
java·mysql·面试
sduwcgg43 分钟前
python的numpy的MKL加速
开发语言·python·numpy
wkj0011 小时前
QuaggaJS 配置参数详解
java·linux·服务器·javascript·quaggajs
钢铁男儿1 小时前
Python 接口:从协议到抽象基 类(定义并使用一个抽象基类)
开发语言·python
暴力求解1 小时前
C++类和对象(上)
开发语言·c++·算法
让我们一起加油好吗1 小时前
【基础算法】枚举(普通枚举、二进制枚举)
开发语言·c++·算法·二进制·枚举·位运算
大锦终1 小时前
【C++】特殊类设计
开发语言·c++