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*/@Overridepublic 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()); }
} 
来源:https://www.cnblogs.com/guanbin-529/p/11784914.html

Callable接口及Futrue接口详解相关推荐

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

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

  2. php支付宝接口参数错误,php支付接口_php支付宝支付接口程序及参数详解

    摘要 腾兴网为您分享:php支付宝支付接口程序及参数详解,作业盒子,智能互联,智联招聘,小番茄等软件知识,以及雷电游戏中心,天气预报软件,live电视直播,otcbtc,手机街机,lq-630k驱动 ...

  3. C#接口归纳总结实例详解

    本篇文章通过实例代码对接口做了详解,需要的朋友可以参考下 C#接口的学习,在编程中,我们经常会用到接口,那什么是接口呢? 接口描述的是可属于任何类或结构的一组相关功能,所以实现接口的类或结构必须实现接 ...

  4. loopback接口、router ID详解

    目录 loop back接口简介: loopback接口应用: router id 简介: 选举规则: loop back接口简介: loopback接口是一种纯软件性质的虚拟接口.loopback接 ...

  5. java切面不需要接口了吗_详解Spring AOP 实现“切面式”valid校验

    why: 为什么要用aop实现校验? answer: spring mvc 默认自带的校验机制 @Valid + BindingResult, 但这种默认实现都得在Controller方法的中去接收B ...

  6. Collection集合类和Map接口各实现类详解

    Java的集合类(collection接口和Map) 一.集合概述 集合:集合是java中提供的一种容器,可以用来存储多个数据. 集合和数组既然都是容器,它们有啥区别呢? 数组的长度是固定的.集合的长 ...

  7. 232接口针脚定义_详解串口通信232/485/422,一文就可以搞定!

    一.RS232基础知识 计算机与计算机或计算机与终端之间的数据传送可以采用串行通讯和并行通讯二种方式.由于串行通讯方式具有使用线路少.成本低,特别是在远程传输时,避免了多条线路特性的不一致而被广泛采用 ...

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

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

  9. java 抽象类,接口,object类详解

    抽象类: 如果一个类没有足够的信息去描绘一个具体的对象,那么这个类就可以叫做抽象类. 也可以叫做:可声明抽象方法的类==>抽象类 注意: <1>抽象类不可以实例化对象,所以它只能被继 ...

最新文章

  1. Docker基础之九: 管理容器的数据
  2. ETSI GS MEC 016,Device application interface
  3. python教程:os.chdir() 基本用法
  4. 解析ASP网页的执行顺序
  5. BZOJ3324 : [Scoi2013]火柴棍数字
  6. php连接数据库(一)
  7. 图文讲解 sqlserver 2000 评测版 数据库过期 的解决方法
  8. ckeditor 部分保存按钮去除_怎样去除mp4视频中的水印呢
  9. 租房管理系统毕业设计Java_java毕业设计_springboot框架的租房管理系统
  10. eplan图纸怎么发给别人_如何保护你的EPLAN图纸
  11. 多模块java项目代码混淆
  12. 电阻屏和电容屏的区别
  13. 操作系统与软件工程学习笔记
  14. 设置树莓派屏幕常亮,禁止树莓派屏幕休眠
  15. 数据分析~matlab plot 坐标、字体、子图
  16. 虚拟现实(VR)、增强现实(AR)、混合现实(MR)
  17. 优化-处理大量定时任务的思路
  18. java算法--冒泡算法
  19. PAT | 1025 反转链表 (25分)【超时问题 + 柳神代码】
  20. WebSocket断开原因

热门文章

  1. 手机录音误删怎么恢复?恢复录音,就这么简单!
  2. 工程造价步骤_工程造价的六个步骤
  3. 只要写了带参构造函数则不会再生成无参构造函数,不管该带参构造函数是否是private的
  4. SELinux工作模式设置(getenforce、setenforce和sestatus命令)
  5. 保险知识之:什么是旅行保险?
  6. C++音视频开发的技术要点总结
  7. springboot-js通过class获取元素并修改css
  8. python调用js接口_最全总结!聊聊 Python 调用 JS 的几种方式
  9. centos关闭防火墙命令(centos重启防火墙命令)
  10. prefetch 和preload_preload和prefetch