博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java多线程系类:JUC线程池:06之Callable和Future(转)
阅读量:6160 次
发布时间:2019-06-21

本文共 4727 字,大约阅读时间需要 15 分钟。

概要

本章介绍线程池中的Callable和Future。

转载请注明出处:

 

Callable 和 Future 简介

  Callable 和 Future 是比较有趣的一对组合。当我们需要获取线程的执行结果时,就需要用到它们。Callable用于产生结果,Future用于获取结果。

1. Callable

Callable 是一个接口,它只包含一个call()方法。Callable是一个返回结果并且可能抛出异常的任务。

为了便于理解,我们可以将Callable比作一个Runnable接口,而Callable的call()方法则类似于Runnable的run()方法。

Callable的源码如下:

public interface Callable
{ V call() throws Exception;}

说明:从中我们可以看出Callable支持泛型。

 

2. Future

Future 是一个接口。它用于表示异步计算的结果。提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。

Future的源码如下:

public interface Future
{ // 试图取消对此任务的执行。 boolean cancel(boolean mayInterruptIfRunning) // 如果在任务正常完成前将其取消,则返回 true。 boolean isCancelled() // 如果任务已完成,则返回 true。 boolean isDone() // 如有必要,等待计算完成,然后获取其结果。 V get() throws InterruptedException, ExecutionException; // 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;}

说明: Future用于表示异步计算的结果。它的实现类是FutureTask,在讲解FutureTask之前,我们先看看Callable, Future, FutureTask它们之间的关系图,如下:

说明

(01) RunnableFuture是一个接口,它继承了Runnable和Future这两个接口。RunnableFuture的源码如下:

public interface RunnableFuture
extends Runnable, Future
{ void run();}

(02) FutureTask实现了RunnableFuture接口。所以,我们也说它实现了Future接口。

 

示例和源码分析(基于JDK1.7.0_40)

我们先通过一个示例看看Callable和Future的基本用法,然后再分析示例的实现原理。

1 import java.util.concurrent.Callable; 2 import java.util.concurrent.Future; 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.ExecutorService; 5 import java.util.concurrent.ExecutionException; 6  7 class MyCallable implements Callable { 8  9     @Override 10     public Integer call() throws Exception {11         int sum    = 0;12         // 执行任务13         for (int i=0; i<100; i++)14             sum += i;15         //return sum; 16         return Integer.valueOf(sum);17     } 18 }19 20 public class CallableTest1 {21 22     public static void main(String[] args) 23         throws ExecutionException, InterruptedException{24         //创建一个线程池25         ExecutorService pool = Executors.newSingleThreadExecutor();26         //创建有返回值的任务27         Callable c1 = new MyCallable();28         //执行任务并获取Future对象 29         Future f1 = pool.submit(c1);30         // 输出结果31         System.out.println(f1.get()); 32         //关闭线程池 33         pool.shutdown(); 34     }35 }

运行结果

4950

结果说明

  在主线程main中,通过newSingleThreadExecutor()新建一个线程池。接着创建Callable对象c1,然后再通过pool.submit(c1)将c1提交到线程池中进行处理,并且将返回的结果保存到Future对象f1中。然后,我们通过f1.get()获取Callable中保存的结果;最后通过pool.shutdown()关闭线程池。

 

1. submit()

submit()在java/util/concurrent/AbstractExecutorService.java中实现,它的源码如下:

public 
Future
submit(Callable
task) { if (task == null) throw new NullPointerException(); // 创建一个RunnableFuture对象 RunnableFuture
ftask = newTaskFor(task); // 执行“任务ftask” execute(ftask); // 返回“ftask” return ftask;}

说明:submit()通过newTaskFor(task)创建了RunnableFuture对象ftask。它的源码如下:

protected 
RunnableFuture
newTaskFor(Callable
callable) { return new FutureTask
(callable);}

 

2. FutureTask的构造函数

FutureTask的构造函数如下:

public FutureTask(Callable
callable) { if (callable == null) throw new NullPointerException(); // callable是一个Callable对象 this.callable = callable; // state记录FutureTask的状态 this.state = NEW; // ensure visibility of callable}

 

3. FutureTask的run()方法

我们继续回到submit()的源码中。

在newTaskFor()新建一个ftask对象之后,会通过execute(ftask)执行该任务。此时ftask被当作一个Runnable对象进行执行,最终会调用到它的run()方法;ftask的run()方法在java/util/concurrent/FutureTask.java中实现,源码如下:

public void run() {    if (state != NEW ||        !UNSAFE.compareAndSwapObject(this, runnerOffset,                                     null, Thread.currentThread()))        return;    try {        // 将callable对象赋值给c。        Callable
c = callable; if (c != null && state == NEW) { V result; boolean ran; try { // 执行Callable的call()方法,并保存结果到result中。 result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } // 如果运行成功,则将result保存 if (ran) set(result); } } finally { runner = null; // 设置“state状态标记” int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); }}

说明:run()中会执行Callable对象的call()方法,并且最终将结果保存到result中,并通过set(result)将result保存。

      之后调用FutureTask的get()方法,返回的就是通过set(result)保存的值。

你可能感兴趣的文章
关于textarea的ie9的maxlength不起作用的问题,请参考如下URL解决。
查看>>
Solr Facet 查询
查看>>
C++类的继承一
查看>>
数据库分库分表(sharding)系列(五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案...
查看>>
巧用VMware Workstation的clone来制作虚拟机模板
查看>>
Spring-Mybatis MapperScannerConfigurer 取不到PropertyPlaceholderConfigurer里的值
查看>>
HP DL380G4服务器前面板指示灯的含义
查看>>
数据结构_树结构
查看>>
常用URL地址
查看>>
每天一个linux命令(19):find 命令概览
查看>>
MySQL kill操作
查看>>
windows下看端口占用
查看>>
Decommissioning a Domain Controller 降域控
查看>>
Character中的奇葩
查看>>
c++书籍推荐
查看>>
轻松监听Azure service health 状态
查看>>
获取SQL SERVER某个数据库中所有存储过程的参数
查看>>
在Linux下编译安装Apache2(2)
查看>>
Method Swizzling 处理一类简单的崩溃
查看>>
AngularJS学习!
查看>>