我们知道线程池通过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. XML解析——Jsoup解析器

    一.Jsoup解析器快速入门案例 Docement对象,文本对象,包含着各个Dom树结构 1.引入Jsoup解析器的jar包放在lib文件夹下后,写java代码 其中, 二.Jsoup对象 1.Jso ...

  2. vue-element-admin 全局loading加载等待

    最近遇到需求: 全局加载loading,所有接口都要可以手动控制是否展示加载等待的功能 当拿到这个需求的时候我是拒绝的,因为我以及局部写好了0.0,这是要大改呀....,没办法老板的要求,只能硬着头皮 ...

  3. SparkPi的编程计算

    Pi的计算方式有很多,本文主要是通过Spark在概论统计的方法对Pi进行求解: 算法说明: 在边长为R的正方形中,其面积为R^2,而其内接圆的面积为pi * R^2 /4 ,圆的面积与正方形的面积比为 ...

  4. Datagird样式

    <Window  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  xmlns:x=&qu ...

  5. 【转】.net core开发windows服务

    .net core开发windows服务 文建Blog

  6. Java数学函数的使用

    Java的Math类中提供了一系列关于数学运算的静态方法,常见的运算整理如下[1] 算数运算 Math.sqrt() // 平方根 Math.cbrt() // 立方根 Math.pow(a, b) ...

  7. IDEA 集成 Docker 插件实现一键远程部署 SpringBoot 应用,无需三方依赖,开源微服务全栈项目有来商城云环境的部署方式

    一. 前言 最近有些童鞋对开源微服务商城项目 youlai-mall 如何部署到线上环境以及项目中 的Dockerfile 文件有疑问,所以写了这篇文章做个答疑以及演示完整的微服务项目发布到线上的流程 ...

  8. UML类图及其JAVA的代码实现

    推荐 : https://my.oschina.net/u/3635618/blog/3165129 http://www.uml.org.cn/oobject/201104212.asp

  9. struts2 中 form-action action-form 的传参方式

    1.  struts2 Action获取表单提交数据 主要有三种方式: 1.1 使用ActionContext类 //获取actionContext对象 ActionContext context = ...

  10. Node.js躬行记(11)——E2E测试

    Cypress是为现代网络构建的前端测试工具,解决了开发人员和 QA 工程师在测试应用程序时面临的关键痛点. 在这个测试框架中包含了E2E测试.集成测试和单元测试(内嵌了Mocha),我们需要的是它的 ...