Callable 和 Future 简介

Callable 和 Future 是比较有趣的一对组合。当我们需要获取线程的执行结果时,就需要用到它们。Callable用于产生结果,Future用于获取结果。
1. Callable
Callable 是一个接口,它只包含一个call()方法。Callable是一个返回结果并且可能抛出异常的任务。
为了便于理解,我们可以将Callable比作一个Runnable接口,而Callable的call()方法则类似于Runnable的run()方法。
Callable的源码如下:
public interface Callable<V> {
V call() throws Exception;
}
说明:从中我们可以看出Callable支持泛型。
2. Future
Future 是一个接口。它用于表示异步计算的结果。提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。
Future的源码如下:
public interface Future<V> {
// 试图取消对此任务的执行。
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<V> extends Runnable, Future<V> {
void run();
}
(02) FutureTask实现了RunnableFuture接口。所以,我们也说它实现了Future接口。
示例和源码分析(基于JDK1.7.0_40)
我们先通过一个示例看看Callable和Future的基本用法,然后再分析示例的实现原理。
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;
class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
int sum = 0;
// 执行任务
for (int i=0; i<100; i++)
sum += i;
//return sum;
return Integer.valueOf(sum);
}
}
public class CallableTest1 {
public static void main(String[] args)
throws ExecutionException, InterruptedException{
//创建一个线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//创建有返回值的任务
Callable c1 = new MyCallable();
//执行任务并获取Future对象
Future f1 = pool.submit(c1);
// 输出结果
System.out.println(f1.get());
//关闭线程池
pool.shutdown();
}
}
运行结果:
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 <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
// 创建一个RunnableFuture对象
RunnableFuture<T> ftask = newTaskFor(task);
// 执行“任务ftask”
execute(ftask);
// 返回“ftask”
return ftask;
}
说明:submit()通过newTaskFor(task)创建了RunnableFuture对象ftask。它的源码如下:
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
2. FutureTask的构造函数
FutureTask的构造函数如下:
public FutureTask(Callable<V> 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<V> 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)保存的值。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Java
# concurrency
# Callable
# Future
# 浅谈在Java中使用Callable、Future进行并行编程
# Java中的Runnable
# FutureTask的比较
# java Callable与Future的详解及实例
# java多线程Future和Callable类示例分享
# java多线程返回值使用示例(callable与futuretask)
# java自定义任务类定时执行任务示例 callable和future接口使用方法
# Java并发编程Callable与Future的应用实例代码
# 是一个
# 如有
# 然后再
# 创建一个
# 新建一个
# 实现了
# 最多
# 将其
# 我们可以
# 这两个
# 可以看出
# 当我们
# 类似于
# 抛出
# 中会
# 为使
# 它只
# 大家多多
# 说它
# 则将
相关文章:
如何用PHP快速搭建CMS系统?
北京专业网站制作设计师招聘,北京白云观官方网站?
如何在沈阳梯子盘古建站优化SEO排名与功能模块?
攀枝花网站建设,攀枝花营业执照网上怎么年审?
宿州网站制作公司兴策,安徽省低保查询网站?
如何快速搭建自助建站会员专属系统?
唐山网站制作公司有哪些,唐山找工作哪个网站最靠谱?
香港服务器如何优化才能显著提升网站加载速度?
建站主机SSH密钥生成步骤及常见问题解答?
家庭服务器如何搭建个人网站?
c# F# 的 MailboxProcessor 和 C# 的 Actor 模型
C#怎么创建控制台应用 C# Console App项目创建方法
如何通过万网虚拟主机快速搭建网站?
建站之星安全性能如何?防护体系能否抵御黑客入侵?
常州自助建站费用包含哪些项目?
网站制作的软件有哪些,制作微信公众号除了秀米还有哪些比较好用的平台?
香港服务器租用费用高吗?如何避免常见误区?
网站制作哪家好,cc、.co、.cm哪个域名更适合做网站?
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
江苏网站制作公司有哪些,江苏书法考级官方网站?
怎么将XML数据可视化 D3.js加载XML
如何通过建站之星自助学习解决操作问题?
制作网站公司那家好,网络公司是做什么的?
我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?
C++如何将C风格字符串(char*)转换为std::string?(代码示例)
网站制作公司排行榜,抖音怎样做个人官方网站
宝塔新建站点为何无法访问?如何排查?
专业公司网站制作公司,用什么语言做企业网站比较好?
javascript基本数据类型及类型检测常用方法小结
建站之星安装提示数据库无法连接如何解决?
如何在宝塔面板创建新站点?
建站VPS推荐:2025年高性能服务器配置指南
电商网站制作价格怎么算,网上拍卖流程以及规则?
海南网站制作公司有哪些,海口网是哪家的?
如何在IIS服务器上快速部署高效网站?
PHP正则匹配日期和时间(时间戳转换)的实例代码
如何确保西部建站助手FTP传输的安全性?
如何快速生成专业多端适配建站电话?
建站之星如何快速生成多端适配网站?
建站之星如何一键生成手机站?
建站之星如何修改网站生成路径?
再谈Python中的字符串与字符编码(推荐)
Swift中switch语句区间和元组模式匹配
如何选择可靠的免备案建站服务器?
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
网站规划与制作是什么,电子商务网站系统规划的内容及步骤是什么?
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?
如何零基础开发自助建站系统?完整教程解析
如何选择高效稳定的ISP建站解决方案?
*请认真填写需求信息,我们会在24小时内与您取得联系。