线程池系列二:一张动图,彻底懂了execute和submit
我们知道线程池通过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的更多相关文章
- 线程池系列二:ThreadPoolExecutor讲解
一.简介 1)线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, i ...
- 13张动图助你彻底看懂马尔科夫链、PCA和条件概率!
13张动图助你彻底看懂马尔科夫链.PCA和条件概率! https://mp.weixin.qq.com/s/ll2EX_Vyl6HA4qX07NyJbA [ 导读 ] 马尔科夫链.主成分分析以及条件概 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- juc线程池原理(二):ThreadPoolExecutor的成员变量介绍
概要 线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析ThreadPoolExecutor类,来了解线程池的原理. ThreadPoolExecutor数据结构 Thread ...
- Java 线程池(二)
简介 在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线 ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
- Java之线程池(二)
关于线程和线程池的学习,我们可以从以下几个方面入手: 第一,什么是线程,线程和进程的区别是什么 第二,线程中的基本概念,线程的生命周期 第三,单线程和多线程 第四,线程池的原理解析 第五,常见的几种线 ...
- 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇
concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...
- java线程池技术(二): 核心ThreadPoolExecutor介绍
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程池技术属于比较"古老"而又比较基础的技术了,本篇博客主要作用是个人技术梳理,没什么新玩意. 一.Java线程池技术的 ...
随机推荐
- 使用zipKin构建NetCore分布式链路跟踪
本文主要讲解使用ZipKin构建NetCore分布式链路跟踪 场景 因为最近公司业务量增加,而项目也需要增大部署数量,K8S中Pod基本都扩容了一倍,新增了若干物理机,部分物理机网络通信存在问题,导致 ...
- docker run配置参数
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] -d, --detach=false 指定容器运行于前台还是后台,默认为false -i, - ...
- Spring系列-SpringBase+IOC
Spring 一.前言 Thinking is more important than learning 本文主要讲述spring 以及它的 IOC原理 代码地址:https://gitee.com/ ...
- UVA 506 System Dependencies(模拟 烂题)
https://vjudge.net/problem/UVA-506 题目是给出了五种指令,DEPEND.INSTALL.REMOVE.LIST.END,操作的格式及功能如下: DEPEND item ...
- html jquey的选择器checkbox,select
1 判断checkbox是否选中 用到 jquery的 is方法 jquery: <div id="divId" class="divTable"> ...
- Docker系列(12)- 部署Tomcat
#官方的使用:我们之前的启动都是后台,停止容器后,容器还是可以看到#docker run -it --rm,一般用来测试,用完就会删除容器,镜像还在[root@localhost ~]# docker ...
- Spirit带你彻底搞懂JS的6种继承方案
JavaScript中实现继承的6种方案 01-原型链的继承方案 function Person(){ this.name="czx"; } function Student(){ ...
- 域名系统-DNS
域名系统DNS 域名系统DNS(Domain Name System)是互联网使用的命名系统,用来把便于人们使用的机器名转化为IP地址,域名系统就是名字系统. 很多应用层的软件经常直接使用DNS.DN ...
- 实现一个简单的侧边导航Winform程序框架
目录 简介 实现导航面板 实现方法 使用方法 实现标题栏 窗体拖拽及最大化 自定义窗体按钮 标题显示 按钮设置 实现状态栏 整体使用 参考文章 简介 每次新项目都要想着界面怎么设计好,但想来想去上位机 ...
- C++默认参数静态绑定
先来看这样一段代码 class Base { public: virtual void print(int a = 1) const { std::cout << "Base & ...