我们知道线程池通过execute方法执行提交的Runnable任务,但Runnable只是执行任务,没有返回任何信息。

【线程池原理:线程池原来是个外包公司,打工人我悟了

若是我们想在异步执行完任务后能够拿到结果。怎么处理呢?

我们可以借助Callable来回去返回结果。线程池为我们提供了另外一种方式执行任务,即submit方法

1、为线程池提交任务

  • execute方法执行Runnable任务
  • submit方法执行Runnable或Callable任务,且能获取任务返回结果

2、流程分解

2.1、execute方法执行Runnable任务

execute方法将Runnable任务交付给线程池执行



2.2、submit方法执行Runnable或Callable任务

2.2.1、创建futureTask对象(也是Runnable对象),包含属性Callable和object;将futureTask对象引用传递给外部


public class FutureTask<V> implements RunnableFuture<V> { /**
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
/** The underlying callable; nulled out after running */
private Callable<V> callable;
/** The result to return or exception to throw from get() */
private Object outcome; public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
}

FutureTask中的状态属性(state)代表任务执行的进度。当任务执行到最终态时,代表任务执行结束。

后面调用get()方法时,判断到最终态才能获取object的值

2.2.2、若传入Runnable任务,将其转为Callable任务,赋值给Callable;

若传入Callable任务,则直接赋值给Callable

public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
         throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
} /**
* A callable that runs given task and returns given result
  */
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
final T result;
    RunnableAdapter(Runnable task, T result) {
         this.task = task;
         this.result = result;
     }
    public T call() {
         task.run();
         return result;
     }
 }

2.2.3、futureTask作为Runnable,execute方法执行此任务(见2.1)

2.2.4、当执行futureTask时,会调用其run方法执行Callable任务

Callable任务若正常返回结果则赋值给object;

若执行异常,则将异常捕获并赋值给object

2.2.5、外部根据futureTask对象引用,调用get()方法,获取到futureTask中的object;

区分是返回结果或异常进行处理

public V get() throws InterruptedException, ExecutionException {
      int s = state;
      if (s <= COMPLETING)
          s = awaitDone(false, 0L);
      return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}

通过get()获取结果的过程:

判断任务是否达到最终态。若达到,则根据状态将outcome值区分处理

若未达到

通过LockSupport.parkNanos(futureTask, nanos);挂起当前线程;

futureTask执行到最终态后会执行LockSupport.unpark(thread);重新恢复 因调用get()而挂起的线程

------The End------

如果这个办法对您有用,或者您希望持续关注,也可以扫描下方二维码或者在微信公众号中搜索

线程池系列二:一张动图,彻底懂了execute和submit的更多相关文章

  1. 线程池系列二:ThreadPoolExecutor讲解

    一.简介 1)线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, i ...

  2. 13张动图助你彻底看懂马尔科夫链、PCA和条件概率!

    13张动图助你彻底看懂马尔科夫链.PCA和条件概率! https://mp.weixin.qq.com/s/ll2EX_Vyl6HA4qX07NyJbA [ 导读 ] 马尔科夫链.主成分分析以及条件概 ...

  3. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  4. juc线程池原理(二):ThreadPoolExecutor的成员变量介绍

    概要 线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析ThreadPoolExecutor类,来了解线程池的原理. ThreadPoolExecutor数据结构 Thread ...

  5. Java 线程池(二)

    简介 在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线 ...

  6. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  7. Java之线程池(二)

    关于线程和线程池的学习,我们可以从以下几个方面入手: 第一,什么是线程,线程和进程的区别是什么 第二,线程中的基本概念,线程的生命周期 第三,单线程和多线程 第四,线程池的原理解析 第五,常见的几种线 ...

  8. 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇

    concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...

  9. java线程池技术(二): 核心ThreadPoolExecutor介绍

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程池技术属于比较"古老"而又比较基础的技术了,本篇博客主要作用是个人技术梳理,没什么新玩意. 一.Java线程池技术的 ...

随机推荐

  1. etcd学习(10)-etcd对比Consul和zooKeeper如何选型

    etcd选型对比 前言 基本架构和原理 etcd Consul ZooKeeper 选型对比 总结 参考 etcd选型对比 前言 对比 Consul, ZooKeeper.选型etcd有那些好处呢? ...

  2. 在EXCEL中批量添加超链接

    在单元格中输入函数 =HYPERLINK(链接位置,[显示文本])

  3. 安卓开发 利用百度识图api进行物体识别

    前文 之前的随笔中,已经通过相机或相册获取到了我们想要的图片,接下来进行识图api的配置工作.我使用的是百度的api,利用python获取信息,并在MainActivity中进行调用来输出信息. 一. ...

  4. input竖直的输入框,文字从上到下排列

    有的时候可能会有这样的需求,一个竖直的输入框,输入信息,文字也是从上到下排列: (但是在移动端或用轮播swiper时不起作用,可以用textarea代替input) <!DOCTYPE html ...

  5. learn git(本地仓库)

    #本地 在Windows上安装Git 在Windows上使用Git,可以从Git官网直接https://git-scm.com/downloads下载,然后按默认选项安装即可. 装完成后,在开始菜单里 ...

  6. 转mybatis返回自增主键,亲测

    重点是获取对象的主键值而不是insert的返回值 Mybatis获取插入数据的主键时,返回值总是1xml里的写法 第一种方式 <insert id="insertLogin" ...

  7. Git(2) - git安装、本地仓库与远程仓库使用详细指南

    git版本控制工具 下载地址:https://www.git-scm.com/download/win选择对应版本的工具,下载后是一个exe执行文件: 常用git命令 命令 作用 git init(在 ...

  8. Java-基础-JDK动态代理

    1. 简介 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 比如:我们在调用 ...

  9. P3288-[SCOI2014]方伯伯运椰子【0/1分数规划,负环】

    正题 题目链接:https://www.luogu.com.cn/problem/P3288 题目大意 给出\(n\)个点\(m\)条边的一张图,没条边\(i\)流量为\(c_i\),费用是\(d_i ...

  10. P4774-[NOI2018]屠龙勇士【EXCRT】

    正题 题目链接:https://www.luogu.com.cn/problem/P4774 题目大意 \(n\)个龙血量为\(a_i\),回复能力为\(p_i\),死亡后掉落剑的攻击力\(t_i\) ...