Callable接口

有两种创建线程的方法-一种是通过创建Thread类,另一种是通过使用Runnable创建线程。但是,Runnable缺少的一项功能是,当线程终止时(即run()完成时),我们无法使线程返回结果。为了支持此功能,Java中提供了Callable接口。

  • 为了实现Runnable,需要实现不返回任何内容的run()方法,而对于Callable,需要实现在完成时返回结果的call()方法。请注意,不能使用Callable创建线程,只能使用Runnable创建线程。
  • 另一个区别是call()方法可以引发异常,而run()则不能。
  • 为实现Callable而必须重写call方法。

// Java program to illustrate Callable
// to return a random number
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask; class CallableExample implements Callable
{ public Object call() throws Exception
{
// Create random number generator
Random generator = new Random(); Integer randomNumber = generator.nextInt(5); // To simulate a heavy computation,
// we delay the thread for some random time
Thread.sleep(randomNumber * 1000); return randomNumber;
}
}

Futrue接口

当call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道该线程返回的结果。为此,可以使用Future对象。将Future视为保存结果的对象–它可能暂时不保存结果,但将来会保存(一旦Callable返回)。因此,Future基本上是主线程可以跟踪进度以及其他线程的结果的一种方式。要实现此接口,必须重写5种方法,但是由于下面的示例使用了库中的具体实现,因此这里仅列出了重要的方法。

  • public boolean cancel(boolean mayInterrupt):用于停止任务。如果尚未启动,它将停止任务。如果已启动,则仅在mayInterrupt为true时才会中断任务。
  • public Object get()抛出InterruptedException,ExecutionException:用于获取任务的结果。如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回结果。
  • public boolean isDone():如果任务完成,则返回true,否则返回false

可以看到Callable和Future做两件事-Callable与Runnable类似,因为它封装了要在另一个线程上运行的任务,而Future用于存储从另一个线程获得的结果。实际上,future也可以与Runnable一起使用。

要创建线程,需要Runnable。为了获得结果,需要future。

Java库具有具体的FutureTask类型,该类型实现Runnable和Future,并方便地将两种功能组合在一起。
可以通过为其构造函数提供Callable来创建FutureTask。然后,将FutureTask对象提供给Thread的构造函数以创建Thread对象。因此,间接地使用Callable创建线程。

1.使用Callable和Future的完整示例

package com.example.thread.callable;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*; /**
* @author: GuanBin
* @date: Created in 下午11:19 2019/10/31
*/
public class TestCallable implements Callable<Object> { private int taskNum; public TestCallable(int taskNum) {
this.taskNum = taskNum;
}

//1,2主要区别是创建线程的方式
public static void main(String[] args) throws ExecutionException, InterruptedException {
test1();
test2(); } /**
* 使用Executors.newFixedThreadPool创建线程池
* @throws InterruptedException
* @throws ExecutionException
*/
private static void test1() throws InterruptedException, ExecutionException {
System.out.println("----程序开始运行----");
Date date1 = new Date();
int taskSize=5;
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new TestCallable(i);
// 执行任务并获取Future对象
Future f = pool.submit(c);
list.add(f);
}
// 关闭线程池
pool.shutdown();
// 获取所有并发任务的运行结果
for (Future f : list) {
// 从Future对象上获取任务的返回值,并输出到控制台
System.out.println(">>>" + f.get().toString()); //OPTION + return 抛异常
}
Date date2 = new Date();
System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");
} /**
* 线程直接使用new Thread来创建
* @throws ExecutionException
* @throws InterruptedException
*/
private static void test2() throws ExecutionException, InterruptedException {
System.out.println("----程序开始运行----");
Date date1 = new Date();
int taskSize=5;
FutureTask[] randomNumberTasks = new FutureTask[5];
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < randomNumberTasks.length; i++) {
Callable c = new TestCallable(i);
// 执行任务并获取Future对象
randomNumberTasks[i]= new FutureTask(c); Thread t = new Thread(randomNumberTasks[i]);
t.start();
} // 获取所有并发任务的运行结果
for (Future f : randomNumberTasks) {
// 从Future对象上获取任务的返回值,并输
System.out.println(">>>" + f.get().toString()); //OPTION + return 抛异常
}
Date date2 = new Date();
System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】"); } /**
* call方法的实现,主要用于执行线程的具体实现,并返回结果
* @return
* @throws Exception
*/
@Override
public Object call() throws Exception {
System.out.println(">>>" + taskNum + "任务启动");
Date dateTmp1 = new Date();
Thread.sleep(1000);
Date dateTmp2 = new Date();
long time = dateTmp2.getTime() - dateTmp1.getTime();
System.out.println(">>>" + taskNum + "任务终止");
return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
}
}

输出

----程序开始运行----
>>>0任务启动
>>>1任务启动
>>>2任务启动
>>>3任务启动
>>>4任务启动
>>>0任务终止
>>>0任务返回运行结果,当前任务时间【1002毫秒】
>>>1任务终止
>>>2任务终止
>>>4任务终止
>>>1任务返回运行结果,当前任务时间【1005毫秒】
>>>2任务返回运行结果,当前任务时间【1005毫秒】
>>>3任务终止
>>>3任务返回运行结果,当前任务时间【1005毫秒】
>>>4任务返回运行结果,当前任务时间【1005毫秒】
----程序结束运行----,程序运行时间【1007毫秒】 Process finished with exit code 0

2.使用Callable和FutureTask的完整示例

// Java program to illustrate Callable and FutureTask
// for random number generation
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask; class CallableExample implements Callable
{ public Object call() throws Exception
{
Random generator = new Random();
Integer randomNumber = generator.nextInt(5); Thread.sleep(randomNumber * 1000); return randomNumber;
} } public class CallableFutureTest
{
public static void main(String[] args) throws Exception
{ // FutureTask is a concrete class that
// implements both Runnable and Future
FutureTask[] randomNumberTasks = new FutureTask[5]; for (int i = 0; i < 5; i++)
{
Callable callable = new CallableExample(); // Create the FutureTask with Callable
randomNumberTasks[i] = new FutureTask(callable); // As it implements Runnable, create Thread
// with FutureTask
Thread t = new Thread(randomNumberTasks[i]);
t.start();
} for (int i = 0; i < 5; i++)
{
// As it implements Future, we can call get()
System.out.println(randomNumberTasks[i].get()); // This method blocks till the result is obtained
// The get method can throw checked exceptions
// like when it is interrupted. This is the reason
// for adding the throws clause to main
}
}
}

启动线程后,与线程的所有交互都使用FutureTask,因为它实现了Future接口。因此,不需要存储Thread对象。使用FutureTask对象,还可以取消任务,检查任务是否完成或尝试获取结果。

3.使用Runnable来获取返回结果的实现

// Java program to illustrate Runnable
// for random number generation
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask; class RunnableExample implements Runnable
{
// Shared object to store result
private Object result = null; public void run()
{
Random generator = new Random();
Integer randomNumber = generator.nextInt(5); // As run cannot throw any Exception
try
{
Thread.sleep(randomNumber * 1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
} // Store the return value in result when done
result = randomNumber; // Wake up threads blocked on the get() method
synchronized(this)
{
notifyAll();
}
} public synchronized Object get()
throws InterruptedException
{
while (result == null)
wait(); return result;
}
} // Code is almost same as the previous example with a
// few changes made to use Runnable instead of Callable
public class RunnableTest
{
public static void main(String[] args) throws Exception
{
RunnableExample[] randomNumberTasks = new RunnableExample[5]; for (int i = 0; i < 5; i++)
{
randomNumberTasks[i] = new RunnableExample();
Thread t = new Thread(randomNumberTasks[i]);
t.start();
} for (int i = 0; i < 5; i++)
System.out.println(randomNumberTasks[i].get());
}
}
 

Callable接口及Futrue接口详解的更多相关文章

  1. 【python3+request】python3+requests接口自动化测试框架实例详解教程

    转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...

  2. OpenCV学习C++接口 Mat像素遍历详解

    OpenCV学习C++接口 Mat像素遍历详解

  3. 微信JS接口汇总及使用详解

    这篇文章主要介绍了微信JS接口汇总及使用详解,十分的全面.详尽,包含分享到朋友圈,分享给朋友,分享到QQ,拍照或从手机相册中选图,识别音频并返回识别结果,使用微信内置地图查看位置等接口,有需要的小伙伴 ...

  4. “全栈2019”Java第六十五章:接口与默认方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. python+requests接口自动化测试框架实例详解

    python+requests接口自动化测试框架实例详解   转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实 ...

  6. STM32接口FSMC/FMC难点详解

    STM32接口FSMC/FMC难点详解 转载   http://blog.sina.com.cn/s/blog_808bca130102x94k.html STM32F767的FMC将外部存储器划分为 ...

  7. Jmeter接口之响应断言详解

    响应断言 : 对服务器的响应进行断言校验 Apply to 应用范围: main sample and sub sample, main sample only , sub-sample only , ...

  8. 接口测试之HTTP协议详解

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

  9. Iterator、Iterable接口的使用及详解

    Java集合类库将集合的接口与实现分离.同样的接口,可以有不同的实现. Java集合类的基本接口是Collection接口.而Collection接口必须实现Iterator接口. 以下图表示集合框架 ...

随机推荐

  1. [炼丹术]YOLOv5训练自定义数据集

    YOLOv5训练自定义数据 一.开始之前的准备工作 克隆 repo 并在Python>=3.6.0环境中安装requirements.txt,包括PyTorch>=1.7.模型和数据集会从 ...

  2. CS5262设计DP转HDMI 4K60HZ +VGA 1080P方案芯片

    CS5262是一款带嵌入式MCU的4通道DisplayPort1.4到HDMI2.0/VGA转换器芯片,设计用于将DP1.4信号源连接到HDMI2.0接收器.CS5262集成了DP1.4兼容接收机和H ...

  3. MySQL高级查询与编程笔记 • 【第1章 数据库设计原理与实战】

    全部章节   >>>> 本章目录 1.1 数据需求分析 1.1.1 数据需求分析的定义 1.1.2 数据需求分析的步骤和方法 1.1.3 数据流程图 1.1.4 数据字典 1. ...

  4. JavaScript交互式网页设计 • 【第8章 jQuery动画与特效】

    全部章节   >>>> 本章目录 8.1 显示隐藏动画效果 8.1.1 show() 方法与hide() 方法 8.1.2 toggle()方法 8.1.3 实践练习 8.2 ...

  5. SpringCloud创建Config多客户端公共配置

    1.说明 基于已经创建好的Spring Cloud配置中心, 在配置中心仅保存一套配置文件, 多个客户端可以通过配置中心读取到相同的配置, 而不需要在每个客户端重复配置一遍, 下面以一个Config ...

  6. .net core系列源码地址介绍

    很早就想写.net core相关教程内容了,但是一方面感觉东西太多了,一方面是太懒了,最近才下定决心,一定要写点东西出来,希望能支持一下国内.net 的尴尬处境 好了,先从.net core开源开始吧 ...

  7. c# - 接口的写法与基本调用

    1.前言 接口与Java基本一样 2.操作 (1)看路径结果 (2) 接口源码: namespace ConsoleApp1 { public interface ILogin { void Eat( ...

  8. vert.x框架与tomcat的关系

    1.前言 大学4年,老师唯一让我们学习的web服务器是tomcat,配置方式是先从官网下载阿帕奇的tomcat文件,然后在开发平台导入,然后再配置web.xml等文件, 是一个可同步可异步请求的服务器 ...

  9. linux光标命令快捷键(常用)

    Ctrl+a 移动到首行 Ctrl+e 移动到尾行 Ctrl+u 将当前光标后面的内容全部删除 (剪辑) ctrl+k 将当前光标前面的内容全部删除 (剪辑) Ctrl+→(左右同理) 移动到下个空格 ...

  10. 【Java常用类】Instant:瞬时

    Instant:瞬时 时间线上的一个瞬时点. 这可能被用来记录应用程序中的事件时间戳,该类型是面向机器的. now():获取本初子午线对应的标准时间 Instant instant = Instant ...