Java多线程系列--“JUC线程池”06之 Callable和Future

转载自  Java多线程系列--“JUC线程池”06之 Callable和Future

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)保存的值。

 


更多内容

1. Java多线程系列--“JUC线程池”02之 线程池原理(一)

2. Java多线程系列--“JUC线程池”03之 线程池原理(二)

3. Java多线程系列--“JUC线程池”04之 线程池原理(三)

4. Java多线程系列--“JUC线程池”05之 线程池原理(四)

5. Java多线程系列--“JUC线程池”01之 线程池架构

6. Java多线程系列目录(共xx篇)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329127.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php array分组,php数组分组简单例子

在php网站开发过程中有时候需要把结果集进行分组&#xff0c;使用php的内置函数array_chunk就可以实现 代码如下复制代码$teamsarray(1,2,3,4,5,6,7,8,9);$teamsarray_chunk($teams,2);print_r($teams);/*Array([0] > Array([0] > 1[1] > 2)[1] > Array([0] > 3…

SuperSocket源码解析之开篇

一 简介 官方介绍&#xff1a;SuperSocket 是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架。你无须了解如何使用 Socket, 如何维护 Socket 连接和 Socket 如何工作&#xff0c;但是你却可以使用 SuperSocket 很容易的开发出一款 Socket 服务器端软件&#…

Java守护线程概述

转载自 Java守护线程概述Java的线程分为两种&#xff1a;User Thread(用户线程)、DaemonThread(守护线程)。 只要当前JVM实例中尚存任何一个非守护线程没有结束&#xff0c;守护线程就全部工作&#xff1b;只有当最后一个非守护线程结束是&#xff0c;守护线程随着JVM一同结束…

php while循环次数,php while循环得到循环次数

php while循环得到循环次数复制代码 代码如下:$link mysql_connect(localhost,root,pwd);mysql_select_db(db);$sql "select region_id,local_name from regions where region_grade1";$result mysql_query($sql);$i 0;while ($row mysql_fetch_assoc($result)) {…

EntityFramework和EntityFramework.Extended使用说明——性能,语法和产生的sql

环境说明:EntityFramework 6.1.3和.Net Framework4.5性能注意事项:https://msdn.microsoft.com/zh-cn/library/cc853327.aspx比较精髓的一点:查询执行的各个阶段中的准备查询,每个唯一查询一次。包括编写查询命令、基于模型和映射元数据生成命令树和定义所返回数据的形状的成本…

三个水桶(看了三遍,想了五遍!)

转载至&#xff1a;微信公众号&#xff1a; 创业励志网 一 有位木匠砍了一树&#xff0c;把它做了三个木桶。 一个装粪&#xff0c;就叫粪桶&#xff0c;众人躲着&#xff1b; 一个装水&#xff0c;就叫水桶&#xff0c;众人用着&#xff1b; 一个装酒&#xff0c;就叫酒桶&…

nginx解析php失败,为什么nginx不能解析php?

只运行过这些代码yum install -y vim wget zip unzip git httpd php php-mysql php-odbc php-ldap php-gd php-mbstring php-xml php-xml-rpc php-bcmath libjpeg* mariadb ;rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarc…

.NET Core amp; ASP.NET Core 1.0在Redhat峰会上正式发布

众所周知&#xff0c;Red Hat和微软正在努力使.NET Core成为Red Hat企业版Linux (RHEL)系统上的一流开发平台选项。这个团队已经一起工作好几个月了,RHEL对.NET有许多需求。今天在RedHat 峰会DevNation 上宣布了.NET Core & ASP.NET Core 1.0 RTM。Red Hat有一个新的关于在…

任务调度(三)——Timer的替代品ScheduledExecutorService简介

转载自 任务调度(三)——Timer的替代品ScheduledExecutorService简介先前的两篇博文《任务调度(一)——jdk自带的Timer》和《任务调度(二)——jdk自带的Timer 动态修改任务执行计划》中&#xff0c;简单介绍了一下Timer&#xff0c;可以实现几本的功能&#xff0c;但是在多线程…

jquery实现动态五角星评分

先上代码&#xff0c;最后附属上我的实现思路&#xff0c;新手做的bug多&#xff0c;大牛勿喷&#xff1a;请看代码&#xff1a; ☆☆☆☆☆<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-trans…

php中时间轴,PHP时间轴函数

26 04 2013PHP时间轴函数Yinchiang | 0我们会经常看见现在许多网站的留言或者评论的时间变得十分有趣&#xff0c;刚刚、3分钟前、1天前等等人性化的时间轴好吧&#xff0c;我承认这个函数是转载的&#xff0c;部分按照自己的需求修改了一点点。/*** 时间轴函数&#xff0c;单位…

开源Asp.Net Core小型社区系统

前言 盼星星盼月亮&#xff0c;Asp.Net Core终于发布啦&#xff01;&#xff01; Asp.Net发布时我还在上初中&#xff0c;没有赶上。但是Asp.Net Core我从beta版本便一直关注。最初项目名叫Asp.Net VNext&#xff0c;然后改名叫Asp.Net 5。最煎熬的是RC1发布后&#xff0c;官方…

Java多线程干货系列(1):Java多线程基础

转载自 Java多线程干货系列&#xff08;1&#xff09;&#xff1a;Java多线程基础前言 多线程并发编程是Java编程中重要的一块内容&#xff0c;也是面试重点覆盖区域&#xff0c;所以学好多线程并发编程对我们来说极其重要&#xff0c;下面跟我一起开启本次的学习之旅吧。 正文…

php accesscontrolalloworigin,设置Access-Control-Allow-Origin实现跨域访问

这篇文章主要介绍了Ajax 设置Access-Control-Allow-Origin实现跨域访问,非常不错&#xff0c;具有参考借鉴价值&#xff0c;需要的朋友可以参考下ajax跨域访问是一个老问题了&#xff0c;解决方法很多&#xff0c;比较常用的是JSONP方法&#xff0c;JSONP方法是一种非官方方法&…

.NET Core:面向未来的开源跨平台开发技术

作为一种全新的开源和跨平台的开发平台&#xff0c;.NET Core 历经两年多的开发&#xff0c;终于在于2016年6月27日针对所有主流服务器和桌面操作系统发布 1.0 RTM 版本。.NET Core 是一种通用开发平台&#xff0c;它包含了自动内存管理和现代化高级开发语言等重要特性&#xf…

Sublime Text 3 快捷键总结(拿走)

以下是个人总结不完全的快捷键总汇&#xff0c;祝愿各位顺利解放自己的鼠标。选择类CtrlD 选中光标所占的文本&#xff0c;继续操作则会选中下一个相同的文本。AltF3 选中文本按下快捷键&#xff0c;即可一次性选择全部的相同文本进行同时编辑。举个栗子&#xff1a;快速选中并…

Java多线程学习

转载自 Java多线程学习本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。在这之前&#xff0c;首先让我们来了解下在操作系统中进程和线程的区别&#xff1a;进程&#xff1a;每个进程都有独立的代码和数据空间&#…

php面试心得,php面试题的总结

这篇文章介绍的内容是关于php面试题的总结&#xff0c;有着一定的参考价值&#xff0c;现在分享给大家&#xff0c;有需要的朋友可以参考一下1. 什么事面向对象&#xff1f;主要特征是什么&#xff1f;面向对象是程序的一种设计方式&#xff0c;它利于提高程序的重用性&#xf…

展望C# 7

译者&#xff1a;雪落无痕 xdj 目前的 C# 编译器&#xff08;即 Roslyn&#xff09;于 2014 年 4 月开源。目前不仅是编译器在 GitHub 上开发&#xff1b;语言的设计也是进行公开的讨论。 这允许感兴趣的各方了解语言下一个版本的样子。这篇文章概述了当前在设计语言新特性时的…

Java 线程池详解及实例代码

转载自 Java 线程池详解及实例代码这篇文章主要介绍了Java 线程池的相关资料,并符实例代码&#xff0c;帮助大家学习参考&#xff0c;需要的朋友可以参考下线程池的技术背景 在面向对象编程中&#xff0c;创建和销毁对象是很费时间的&#xff0c;因为创建一个对象要获取内存资…