今天碰到一个需要获取线程返回结果的业务场景,所以了解到了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两个接口 获取线程返回结果的更多相关文章

  1. python获取线程返回值

    python获取线程返回值 前言 工作中的需求 将前端传过来的字符串信息通过算法转换成语音,并将语音文件返回回去 由于算法不是我写的,只需要调用即可,但是算法执行速度相当缓慢 我的优化思路是,将前端的 ...

  2. Callable 获取线程返回值

    allable与 Future 两功能是Java在兴许版本号中为了适应多并法才增加的,Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它 ...

  3. android两种方式获取AsyncTask返回值

    获取AsyncTask返回值,在Activity中使用. 引用链接:https://www.oschina.net/code/snippet_725438_49858#72630 [1].[代码] [ ...

  4. Android多线程的研究(8)——Java5于Futrue获取线程返回结果

    我们先来看看ExecutorService操作的方法: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGF3YW5nYW5iYW4=/font/5a6L5 ...

  5. Android多线程研究(8)——Java5中Futrue获取线程返回结果

    我们先来看一下ExecutorService中的执行方法: 在上一篇中我们使用了execute方法启动线程池中的线程执行,这一篇我们来看看submit方法的使用:submit提交一个返回值的任务用于执 ...

  6. 异步模式模式Future(结合Callable可以获取线程返回结果)

    submit 和 excute是有啥区别 如果有这样的需求: 多线程实现下载,提高效率. 不论是Thread类还是Runnable接口重写run方法,有个特点就是没有返回值~~~~~~ 我都主线程 如 ...

  7. Android(java)学习笔记66:实现Runnable接口创建线程 和 使用Callable和Future创建线程

    1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...

  8. Android(java)学习笔记6:实现Runnable接口创建线程 和 使用Callable和Future创建线程

    1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...

  9. 多线程----Thread类,Runnable接口,线程池,Callable接口,线程安全

    1概念 1.1进程 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 任务管理器中: 1.2线程 线程是进程中的一个执行单元 ...

随机推荐

  1. ASP.NET MVC4.0+ WebAPI+EasyUI+KnockOutJS快速开发框架 通用权限管理系统

    1.基于 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发 2.采用MVC的框架模式,具有耦合性低.重用性高.生命周期成本低.可维护性高.有利软件 ...

  2. keepalived 安装配置

    keepalived介绍 1. keepalived 是lvs 的扩展项目,因此它们之间具备良好的兼容性. 2. 通过对服务器池对象的健康检查,实现对失效机器/服务的故障隔离. 3. 负载均衡器之间的 ...

  3. css :target

    花了半小时在找如果完成:target的问题 需求:点击<a href="#Main">Main</a>时,会触发:target 效果 结果在网络上没有找到, ...

  4. HTML第二课

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  5. Springboot 整合 Dubbo/ZooKeeper 详解 SOA 案例

    摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!   “看看星空,会觉得自己很渺小,可能我们在宇宙中从来就是一个偶然.所以,无论什么事情,仔细想一 ...

  6. 一个可以将 json 字符串 直接绑定到 view 上的Android库

    android-data-binding 这是一个可以将 json 字符串 直接绑定到 view 上的库, 不用先将 json 转换为 model 类. 传送门(https://github.com/ ...

  7. 2005: [Noi2010]能量采集

    2005: [Noi2010]能量采集 Time Limit: 10 Sec  Memory Limit: 552 MBSubmit: 1831  Solved: 1086[Submit][Statu ...

  8. Javascript基础知识小测试(一)

    这里罗列了<你不知道的js>上卷的一些知识点以及小问题,如果你想巩固一下js那么就和我一起来看看吧. 如果你能不看书就回答上80%的问题说明你js的这一部分学得还不错,再接再厉. 作用域和 ...

  9. win8和ubuntu双系统

    硬盘安装的话只要分够内存和做好开机启动项就好了,u盘安装要注意分区(挂载)了推荐: http://wenku.baidu.com/view/5052f19b51e79b8968022623.html ...

  10. springmvc基础学习3---注解简单理解

    1:@Controller 用来注解这个bean是MVC模型中的一个C 会被spring的auto-scan扫到纳入管理.Spring mvc框架中的action层注入,也就是控制层.控制器Contr ...