深入Callable及Runnable两个接口 获取线程返回结果
今天碰到一个需要获取线程返回结果的业务场景,所以了解到了Callable接口。
先来看下下面这个例子:
public class ThreadTest { public static void main(String[] args) throws Exception {
ExecutorService exc = Executors.newCachedThreadPool();
try {
String result = null;
FutureTask<String> task = (FutureTask<String>) exc.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i <; i++) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getClass() + "::线程执行中.." + i);
}
}
}, result); System.out.println("task return value:" + task.get()); FutureTask<String> callableTask = (FutureTask<String>) exc.submit(new Callable<String>() { @Override
public String call() throws InterruptedException {
for (int i = 0; i <; i++) {
Thread.sleep(100L);
System.out.println(this.getClass() + "::线程执行中.." + i);
}
return "success";
} }); System.out.println("提前出结果了 task return value:" + task.get()); System.out.println("callableTask return value:" + callableTask.get()); } finally {
exc.shutdown();
} } }
运行结果如下:
class thread.ThreadTest$1::线程执行中..0
class thread.ThreadTest$1::线程执行中..1
class thread.ThreadTest$1::线程执行中..2
class thread.ThreadTest$1::线程执行中..3
class thread.ThreadTest$1::线程执行中..4
class thread.ThreadTest$1::线程执行中..5
class thread.ThreadTest$1::线程执行中..6
class thread.ThreadTest$1::线程执行中..7
class thread.ThreadTest$1::线程执行中..8
class thread.ThreadTest$1::线程执行中..9
task return value:null
提前出结果了 task return value:null
class thread.ThreadTest$2::线程执行中..0
class thread.ThreadTest$2::线程执行中..1
class thread.ThreadTest$2::线程执行中..2
class thread.ThreadTest$2::线程执行中..3
class thread.ThreadTest$2::线程执行中..4
class thread.ThreadTest$2::线程执行中..5
class thread.ThreadTest$2::线程执行中..6
class thread.ThreadTest$2::线程执行中..7
class thread.ThreadTest$2::线程执行中..8
class thread.ThreadTest$2::线程执行中..9
callableTask return value:success
可以得到以下几点:
1 Runnable,Callable两个接口方法体不一样,前者为run,后者为call,且返回值也不一样;
2 Runnable接口由于run方法返回void所以无法解决线程成功后返回相应结果的问题;但是实现Callable接口的线程类可以,因为Callable的执行方法体call方法
可以返回对象。
3 由于runnable接口没有返回值,所以FutureTask为了解决此问题将runnable线程类通过支配器转换为callable线程。
4 当通过task对象调用get方法时,已经执行完成的现成可以立刻得到返回结果,但是还没执行完的线程一直在等待。
下面进入源码看看:
线程池执行submit方法时进入AbstractExecutorService类中的submit
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
这里好理解,将线程放入任务,由线程池的execute方法去执行。
执行完成后,当调用get方法时,会进入FutureTask的get方法:
public V get() throws InterruptedException, ExecutionException {
int s = state;
//当线程状态为新建活着执行中时一直调用awaitDone方法
if (s <= COMPLETING)
//循环判断线程状态是否已经执行成功,如果执行成功返回线程状态;其中还包括线程取消,中断等情况的判断。可参见下方源码。
//所以这里便是上面例子中为什么线程执行成功后即可立即得到结果,如果还没有执行成功
s = awaitDone(false, 0L);
//线程状态正常返回结果
return report(s);
}
awaitDone源码
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
} int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}
@SuppressWarnings("unchecked")
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);
}
然后我们来看看FutureTask是如何对runnable线程进行转换的。代码也很简单:
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, 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;
}
}
深入Callable及Runnable两个接口 获取线程返回结果的更多相关文章
- python获取线程返回值
python获取线程返回值 前言 工作中的需求 将前端传过来的字符串信息通过算法转换成语音,并将语音文件返回回去 由于算法不是我写的,只需要调用即可,但是算法执行速度相当缓慢 我的优化思路是,将前端的 ...
- Callable 获取线程返回值
allable与 Future 两功能是Java在兴许版本号中为了适应多并法才增加的,Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它 ...
- android两种方式获取AsyncTask返回值
获取AsyncTask返回值,在Activity中使用. 引用链接:https://www.oschina.net/code/snippet_725438_49858#72630 [1].[代码] [ ...
- Android多线程的研究(8)——Java5于Futrue获取线程返回结果
我们先来看看ExecutorService操作的方法: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGF3YW5nYW5iYW4=/font/5a6L5 ...
- Android多线程研究(8)——Java5中Futrue获取线程返回结果
我们先来看一下ExecutorService中的执行方法: 在上一篇中我们使用了execute方法启动线程池中的线程执行,这一篇我们来看看submit方法的使用:submit提交一个返回值的任务用于执 ...
- 异步模式模式Future(结合Callable可以获取线程返回结果)
submit 和 excute是有啥区别 如果有这样的需求: 多线程实现下载,提高效率. 不论是Thread类还是Runnable接口重写run方法,有个特点就是没有返回值~~~~~~ 我都主线程 如 ...
- Android(java)学习笔记66:实现Runnable接口创建线程 和 使用Callable和Future创建线程
1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...
- Android(java)学习笔记6:实现Runnable接口创建线程 和 使用Callable和Future创建线程
1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...
- 多线程----Thread类,Runnable接口,线程池,Callable接口,线程安全
1概念 1.1进程 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 任务管理器中: 1.2线程 线程是进程中的一个执行单元 ...
随机推荐
- H5缓存-Manifest
在app中更新h5页面一直有缓存问题.默认什么都不做的情况下,app有一定的空间缓存页面.一开始更新之后会马上加载,等到app缓存空间上来之后更新就无法下载了.安卓能够清理缓存空间,ios就只能卸载重 ...
- JavaScript中非常强大的Swiper
刚开始学习javaScript的时候,做轮播图(比如手机淘宝首页的广告位置)是使用html和css结合js的for语句.传参等知识写出来的.但学到js事件时,其实用Swiper更加好写,Swiper的 ...
- Python字典详解
转载请注明出处 Python字典(dict)是一个很常用的复合类型,其它常用符合类型有:数组(array).元组(touple)和集合(set).字典是一个key/value的集合,key可以是任意可 ...
- JAVA开发环境搭建 - JDK安装及环境变量配置
1.前提条件 系统:本教程以WIN7系统为例 JDK:本教程以jdk-7u79-windows-x64为例 2.安装步骤 双击运行JDK安装程序
- WeMall商城系统的Android app商城中的wemall-mobile代码
wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改. [适合研究学习,支持wemall3.x版本] 1.快 ...
- SPM HW1 A project
项目分析 --民航航班异常轨迹可视分析 最近完成的一个项目是一个可视化大作业--民航航班异常轨迹可视分析.要求利用已给的8G飞机的飞行记录数据,将飞机的飞行轨迹在浏览器中进行飞行轨迹高维可视化以及对异 ...
- 【原创】有关Buffer使用,让你的日志类库解决IO高并发写
[本人原创],欢迎交流和分享技术,转载请附上如下内容: 作者:itshare [转自]http://www.cnblogs.com/itshare/ 通常我们知道,当一个日志借口被外部程序多个线程请求 ...
- 菜鸟Scrum敏捷实践系列(一)用户故事概念
菜鸟Scrum敏捷实践系列索引 菜鸟Scrum敏捷实践系列(一)用户故事概念 菜鸟Scrum敏捷实践系列(二)用户故事验收 菜鸟Scrum敏捷实践系列(三)用户故事的组织---功能架构的规划 敏捷开发 ...
- SQLServer 数据库不能重命名的解决方案
无法用排他锁锁定该数据库,以执行该操作 SQL Server2008 因为可能其他用户在占用着该数据库 解决办法为 把数据库先改为单用户的,再改数据库名,再改回多用户的 USE [master] GO ...
- download 下载文件 IE兼容性处理
根据CANIUSE(http://caniuse.com/#search=download)download兼容性如下图所示: 如上图所示,IE浏览器是不支持的. 1.测试代码: <!docty ...