Java Callable和Future简述
创建线程的两种方式,一种是直接继承Thread,另外一种就是实现Runnable接口。这两种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。
一、Runnable接口
先看一下java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法:
- public interface Runnable {
- public abstract void run();
- }
由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。
二、Callable接口
Callable接口位于java.util.concurrent包下,在它里面也只声明了一个方法,只不过这个方法叫做call()。
- public interface Callable<V> {
- V call() throws Exception;
- }
可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。Callable接口可以看作是Runnable接口的补充,call方法带有返回值,并且可以抛出异常。
三、FutureTask类
如何获取Callable的返回结果呢?一般是通过FutureTask这个中间媒介来实现的。整体的流程是这样的:
把Callable实例当作参数,生成一个FutureTask的对象,然后把这个对象当作一个Runnable,作为参数另起线程。
3.1 FutureTask的结构
3.2 FutureTask的启动
由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。下面以Thread包装线程方式启动来说明一下。
- import java.util.concurrent.Callable;
- import java.util.concurrent.FutureTask;
- public class Demo {
- public static void main(String[] args) throws Exception {
- Callable<Integer> call = new Callable<Integer>() {
- public Integer call() throws Exception {
- System.out.println("计算线程正在计算结果...");
- Thread.sleep(3000);
- return 1;
- }
- };
- FutureTask<Integer> task = new FutureTask<>(call);
- Thread thread = new Thread(task);
- thread.start();
- System.out.println("main线程干点别的...");
- Integer result = task.get();
- System.out.println("从计算线程拿到的结果为:" + result);
- }
- }
四、Future接口
FutureTask继承体系中的核心接口是Future。Future的核心思想是:一个方法,计算过程可能非常耗时,等待方法返回,显然不明智。可以在调用方法的时候,立马返回一个Future,可以通过Future这个数据结构去控制方法f的计算过程。
这里的控制包括:
get方法:获取计算结果(如果还没计算完,也是必须等待的)
cancel方法:还没计算完,可以取消计算过程
isDone方法:判断是否计算完
isCancelled方法:判断计算是否被取消
补充:同样是获取线程的计算结果,Java则显得很繁琐,而C语言的实现则简单的多。看下面的例子
假设有两个函数:
- void * dose_do(void * a) {
- for (int i = 0; i < 5; i++) {
- sleep(1);
- puts("does_do");
- }
- return NULL;
- }
- void * dose_not(void * a) {
- for (int i = 0; i < 5; i++) {
- sleep(1);
- puts("does_not");
- }
- return NULL;
- }
这两个函数都返回了void指针,因为void指针可以指向存储器中任何数据类型的数据,线程函数的返回类必须是void *。
一、创建线程
创建线程可以使用多种线程库,在此我们使用最流行的一种:POSIX线程库,也叫pthread。必须包含#include <pthread.h>头文件。我们使用pthread_create() 函数创建并运行一个线程,而且每个线程都需要把线程信息保存在一个pthread_t类型的数据中。
- // 线程对象
- pthread_t t0;
- pthread_t t1;
- if (pthread_create(&t0, NULL, dose_not, NULL) == -1) {
- error("无法创建线程t0");
- }
- if (pthread_create(&t1, NULL, dose_do, NULL) == -1) {
- error("无法创建线程t1");
- }
二、获取线程返回值
上边的两个函数将会独立的在线程中运行直到结束,但是我们需要知道这两个函数什么时候结束。可以使用pthread_join()函数等待函数结束,它会接受线程函数的返回值,并保存在一个void *类型的数据中。那么这个函数是如何得知线程结束的呢?当得到线程函数的返回值的时候,就表明线程函数结束了。这也是为什么线程函数必须要有返回值的原因。
- void *result;
- if (pthread_join(t0, &result) == -1) {
- error("无法回收线程t0");
- }
- if (pthread_join(t1, &result) == -1) {
- error("无法回收线程t1");
- }
我们来看全部代码:
- #include <stdio.h>
- #include <pthread.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- // 错误处理函数
- void error(char *msg) {
- fprintf(stderr, "Error: %s %s", msg, strerror(errno));
- exit(1);
- }
- void * dose_not(void * a) {
- for (int i = 0; i < 5; i++) {
- sleep(1);
- puts("does_not");
- }
- return NULL;
- }
- void * dose_do(void * a) {
- for (int i = 0; i < 5; i++) {
- sleep(1);
- puts("does_do");
- }
- return NULL;
- }
- int main(int argc, const char * argv[]) {
- // 线程对象
- pthread_t t0;
- pthread_t t1;
- if (pthread_create(&t0, NULL, dose_not, NULL) == -1) {
- error("无法创建线程t0");
- }
- if (pthread_create(&t1, NULL, dose_do, NULL) == -1) {
- error("无法创建线程t1");
- }
- void *result;
- if (pthread_join(t0, &result) == -1) {
- error("无法回收线程t0");
- }
- if (pthread_join(t1, &result) == -1) {
- error("无法回收线程t1");
- }
- return 0;
- }
from: http://www.threadworld.cn/archives/39.html
Java Callable和Future简述的更多相关文章
- 基于java callable及future接口解决生产者消费者问题
这两天复习java线程时,把java里面的线程基本知识点与jdk1.5以后新添加的一些类的使用都了解了一下,借用生产者消费者的问题来将他们实践一下. 题目:(题目在csdn一大牛的空间找的) 生产者- ...
- 【Todo】Java Callable和Future学习
参考这篇文章:http://blog.csdn.net/ghsau/article/details/7451464 还有一个系列<Java多线程>
- Java Callable 与 Future
- Java Callable接口与Future接口的两种使用方式
Java Callable.Future的两种使用方式Callable+Futurepublic class Test { public static void main(String[] args) ...
- Java Callable Future Example(java 关于Callable,Future的例子)
Home » Java » Java Callable Future Example Java Callable Future Example April 3, 2018 by Pankaj 25 C ...
- Java线程之Callable、Future
简述 在多线程中有时候我们希望一个线程执行完毕后可以返回一些值,在java5中引入了java.util.concurrent.Callable接口,它类似于Runnable接口,但是Callable可 ...
- java多线程系类:JUC线程池:06之Callable和Future(转)
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java多线程系列--“JUC线程池”06之 Callable和Future
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java并发编程:Callable、Future和FutureTask
作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...
随机推荐
- 028 -bash-4.1$ 出现故障的原理及解决办法?
最近在搭建分布式的时候,出现了这个问题,很不爽.下面是我的解决方式. 1.在用户下删除bash rm -rf /home/beifeng/.bash* 2.拷贝 cp /etc/skel/.bash* ...
- 001.WordPress建站部署
一 WordPress简介 WordPress是一种使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站.也可以把 WordPress当作一个内容管理系统( ...
- .NET工作准备--01前言
01应聘须知(已过时) -1.了解软件开发大环境.-2.准备简历:不宜超过一页,永远准备中文,模板. -3.渠道:3大网站,中华英才,前程无忧(51job最给力),智联招聘.现在还有猎聘网和100程序 ...
- 网站截图工具EyeWitness
网站截图工具EyeWitness 在网页分析和取证中,往往需要大批量的网站截图.Kali Linux提供了一款网站批量截图工具EyeWitness.该工具不仅支持网址列表文件,还支持Nmap和Ne ...
- HTML Agility Pack:簡單好用的快速 HTML Parser
HTML Agility Pack:簡單好用的快速 HTML Parser Codeplex 軟體套件(Package)資訊 套件名稱 HTML Agility Pack 作者 Simon Mouri ...
- Codeforces.810D.Glad to see you!(交互 二分)
题目链接 \(Description\) 有一个大小为\(k\)的集合\(S\),元素两两不同且在\([1,n]\)内.你可以询问不超过\(60\)次,每次询问你给出\(x,y\),交互库会返回\(\ ...
- 使用清华源和阿里源替代Ubuntu源
sudo nano /etc/apt/source.list 替换为如下文本 # 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 deb https://mirrors. ...
- 群晖NAS使用Docker安装迅雷离线下载出现the active key is not valid.
出现这种情况多半是挂了,也有可能是不稳定的网络,重装Docker镜像可能会解决,只有不断试,没什么好的解决方法.
- C# 读带复选框的excel,写excel并设置字体、边框、背景色
这是一篇excel读写功能大汇总,通过C#调用Microsoft.Office.Interop.Excel.dll才能完成任何复杂格式excel的读写操作. 本文需要读取的excel格式如下: 可见表 ...
- 用AB对Webservice做压力测试
AB工具下载 AB工具介绍见 web压力测试工具 下载ab工具后放到任意目录下,从命令行打开ab.exe 使用以下命令测试Webservice ab -c 100 -n 1000 -p zip.txt ...