先看一段FutureTask获取线程返回值简单应用的代码,以下基于jdk8进行源码分析。
package com.lanhuigu.demo.createthread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 实现Callable接口,获取线程执行返回值
* @author yihonglei
* @date 2018/9/12 16:43
*/
public class MyCallable implements Callable<String> {
/**
* 实现Callable中的call方法
* @author yihonglei
* @date 2018/9/12 17:01
*/
public String call() throws Exception {
return "Test Callable";
}
public static void main(String[] args) {
/** 根据MyCallable创建FutureTask对象 */
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
try {
/** 启动线程 */
new Thread(futureTask).start();
/** 获取线程执行返回值 */
String s = futureTask.get();
/** 打印返回值 */
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
程序运行结果:
成功拿到了线程执行的返回值。
以下从源码角度分析拿到返回值的全过程,首先需要简单了解下Callable和FutureTask的结构。
Callable是一个函数式接口,源码如下:
package java.util.concurrent;
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
该接口有一个call方法,返回任意类型值。
FutureTask实现RunnableFuture接口,而RunnableFuture继承了Runnable, Future<V>,源码如下:
package java.util.concurrent;
import java.util.concurrent.locks.LockSupport;
public class FutureTask<V> implements RunnableFuture<V> {
......
}
package java.util.concurrent;
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
所以FutureTask具有Runnable和Future功能,因此,在上面的Demo中,以下代码具有Runable特性:
/** 根据MyCallable创建FutureTask对象 */
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
创建线程对象,通过start()方法启动线程:
/** 启动线程 */
new Thread(futureTask).start();
start()方法源码如下:
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
// 本地方法
private native void start0();
start()方法最后会调用本地方法,由JVM通知操作系统,创建线程,最后线程通过JVM访问到Runnable中的run()方法。
而FutureTask实现了Runnable的run()方法,看下FutureTask中的run()方法源码:
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
/**
这里的callable就是我们创建FutureTask的时候传进来的MyCallable对象,
该对象实现了Callable接口的call()方法。
*/
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
/**
调用Callable的call方法,即调用实现类MyCallable的call()方法,
执行完会拿到MyCallable的call()方法的返回值“Test Callable”。
*/
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
/** 将返回值传入到set方法中,这里是能获取线程执行返回值的关键 */
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
从run()方法源码可以知道,MyCallabel执行call()方法的返回值被传入到了一个set()方法中,能拿到线程返回值最关键的
就是这个FutureTask的set()方法源码:
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
/**
将MyCallable执行call()方法的返回值传进来赋值给了outcome,
这个outcome是FutureTask的一个成员变量。
该变量用于存储线程执行返回值或异常堆栈,通过对应的get()方法获取值。
private Object outcome;
*/
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
到这里,得出一个结论就是,MyCallable执行的call()方法结果通过FutureTask的set()方法存到了成员变量outcome中,
通过我们熟悉的get方法就可以获取到outcome对应赋的值。
在Demo中获取返回值的代码:
/** 获取线程执行返回值 */
String s = futureTask.get();
FutureTask中get()方法的源码:
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
/** 调用report方法 */
return report(s);
}
private V report(int s) throws ExecutionException {
/** outcome赋值给Object x */
Object x = outcome;
if (s == NORMAL)
/** 返回outcome的值,也就是线程执行run()方法时通过set()方法放进去的MyCallable的call()执行的返回值 */
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
get()方法调用report()方法,report()方法会将outcome赋值并返回,set方法成功拿到返回的outcome,
也就是MyCallable()的call()方法执行结果。
到这里,我们大概理解了FutureTask.get()能拿到线程执行返回值的本质原理,也就基于FutureTask的成员变量
outcome进行的set赋值和get取值的过程。
下面简单总结一下过程:
1)FutureTask通过MyCallable创建;
2)new Thread()创建线程,通过start()方法启动线程;
3)执行FutureTask中的run()方法;
4)run()方法中调用了MyCallable中的call()方法,拿到返回值set到FutureTask的outcome成员变量中;
5)FutureTask通过get方法获取outcome对象值,从而成功拿到线程执行的返回值;
其实,本质上就是一个基于FutureTask成员变量outcome进行的set和get的过程,饶了一圈而已。
---------------------
原文:https://blog.csdn.net/yhl_jxy/article/details/82664829
相关推荐
主要介绍了多线程返回值使用示例(callable与futuretask),需要的朋友可以参考下
主要介绍了futuretask源码分析(推荐),小编觉得还是挺不错的,这里给大家分享下,供各位参考。
FutureTask是可取消的异步的计算任务,它可以通过线程池和线程对象执行,一般来说是FutureTask用于耗时的计算。 二,FutureTask继承图 三,未来任务源码 FutureTask的七种状态 状态(state) 值 描述 新的 0 任务...
主要介绍了Java线程池FutureTask实现原理详解,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
FutureTask底层实现分析,有了FutureTask主线程要想获得工作线程(异步计算线程)的结果变得比较简单
主要介绍了futuretask用法及使用场景介绍,小编觉得挺不错的,这里分享给大家,供大家参考。
主要为大家详细介绍了Java中Future、FutureTask原理以及与线程池的搭配使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
获取线程执行结果的原理:以 ThreadPoolExecutor 为例(实现 ExecutorService 接口), 其 submit() 方法提交任务, 返回 一个 FutureTask 实例,这个实例 outcome 成员变量用于存储线程的执行结果, state 成员变量...
Java并发包源码分析(JDK1.8):囊括了java.util.concurrent包中大部分类的源码分析,其中涉及automic包,locks包...对每个类的核心源码进行详细分析,笔记详细,由浅入深,层层深入,带您剖析并发编程原理
多线程机制 1 1、 Runnable接口与Thread类 1 2、 两个创建线程方法的比较 3 3、 几个常用的改变线程状态的方法 3 4、 线程的同步机制 8 ...10、 Callable结合FutureTask的多线程使用(免打扰模式) 24
程序猿学社的GitHub,欢迎Star ...本文已记录到github,形成...源码分析2.1 第一步,实现Callable接口2.2 FutureTask类结构图2.3 RunableFuture接口2.4 Runnable接口2.5 Future接口2.6 FutureTask源码分析后记 前言 通过上
3.通过Callable和FutureTask创建线程 4.通过线程池创建线程 前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果 后面两种可以归结成一类:有返回值,...
NULL 博文链接:https://dingran.iteye.com/blog/1864962
多种创建线程的方式案例演示(一)带返回值的方式.mp4 多种创建线程的方式案例演示(二)使用线程池.mp4 Spring对并发的支持:Spring的异步任务.mp4 使用jdk8提供的lambda进行并行计算.mp4 了解多线程所带来的安全...
最代码,http://www.zuidaima.com/share/1724478138158080.htm 的代码及例子
主要介绍了Java FutureTask类使用案例解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值析,需要的朋友可以参考下
主要介绍了简谈java并发FutureTask的实现,FutureTask都是用于获取线程执行的返回结果。文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下
这是一个集齐了runnable与callnable的线程处理包,自动集齐全部功能,只需引用即可
主要介绍了Java中的Runnable,Callable,Future,FutureTask的比较的相关资料,需要的朋友可以参考下
Java 多线程与并发(17_26)-JUC线程池_ FutureTask详解