Callable接口、Runable接口、Future接口
转自:https://www.cnblogs.com/felixzh/p/6044371.html
参考:https://blog.csdn.net/qq_36761831/article/details/90517323
1. Callable与Runable区别
Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理。Thread类、Runnable接口和Java内存管理模型使得多线程编程简单直接。
但Thread类和Runnable接口都不允许声明检查型异常,也不能定义返回值。没有返回值这点稍微有点麻烦。不能声明抛出检查型异常则更麻烦一些。
public void run()方法契约意味着你必须捕获并处理检查型异常。即使你小心地保存了异常信息(在捕获异常时)以便稍后检查,但也不能保证这个类(Runnable对象)的所有使用者都读取异常信息。
你也可以修改Runnable实现的getter,让它们都能抛出任务执行中的异常。但这种方法除了繁琐也不是十分安全可靠,你不能强迫使用者调用这些方法,程序员很可能会调用join()方法等待线程结束然后就不管了。
但是现在不用担心了,以上的问题终于在1.5中解决了。Callable接口和Future接口的引入以及他们对线程池的支持优雅地解决了这两个问题。
不管用哪种方式创建线程,其本质都是Callable接口与Runable接口。两者都是可被其它线程执行的任务!!区别是:
(1)Callable规定的方法是call(),而Runnable规定的方法是run()。(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。(3)call()方法可抛出异常,而run()方法是不能抛出异常的。(4)运行Callable任务可拿到一个Future对象。
2.Future
如上所说,Callable任务返回Future对象。即:Callable和Future一个产生结果,一个拿到结果。
Future 表示异步计算的结果。Future接口中有如下方法:
- boolean cancel(boolean mayInterruptIfRunning)
取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束
- boolean isCancelled()
任务是否已经取消,任务正常完成前将其取消,则返回 true
- boolean isDone()
任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true
- V get()
等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException
- V get(long timeout, TimeUnit unit)
同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException
Future接口提供方法来检测任务是否被执行完,等待任务执行完获得结果。也可以设置任务执行的超时时间,这个设置超时的方法就是实现Java程序执行超时的关键。
所以,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。
三个简单的小例子,体会一下:
package com.zyf.Future;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;public class FutureGetTimeOut1 { public static void main(String[] args){ int timeout = 2; ExecutorService executor = Executors.newSingleThreadExecutor(); Boolean result = false; Future<Boolean> future = executor.submit(new TaskThread("发送请求"));//将任务提交给线程池try { result = future.get(timeout, TimeUnit.SECONDS);// result = future.get(timeout, TimeUnit.MILLISECONDS); //1System.out.println("发送请求任务的返回结果: "+result); //2} catch (InterruptedException e) { System.out.println("线程中断出错。"); future.cancel(true);// 中断执行此任务的线程 } catch (ExecutionException e) { System.out.println("线程服务出错。"); future.cancel(true);} catch (TimeoutException e) {// 超时异常 System.out.println("超时。"); future.cancel(true); }finally{ System.out.println("线程服务关闭。"); executor.shutdown(); } } static class TaskThread implements Callable<Boolean> { private String t; public TaskThread(String temp){ this.t= temp; } public Boolean call() { //for用于模拟超时for(int i=0;i<999999999;i++){ if(i==999999998){ System.out.println(t+"成功!"); } if (Thread.interrupted()){ //很重要 return false; } } System.out.println("继续执行.........."); return true; } }
}
package com.zyf.Future;import java.util.concurrent.*;public class FutureGetTimeOut2 {public static void main(String[] args) {final ExecutorService service = Executors.newFixedThreadPool(1);TaskThread taskThread = new TaskThread();System.out.println("提交任务...begin");Future<Object> taskFuture = service.submit(taskThread);System.out.println("提交任务...end");try {Object re = taskFuture.get(60000, TimeUnit.MILLISECONDS);// 超时设置System.out.println(re);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();} catch (TimeoutException e) {System.out.println("超时 取消任务");taskFuture.cancel(true);System.out.println("超时 取消任务OK");} finally {service.shutdown();}}
}class TaskThread implements Callable<Object> {public Object call() throws Exception {String result = "空结果";try {System.out.println("任务开始....");//修改sleep 的值测试超时Thread.sleep(500);result = "正确结果";System.out.println("任务结束....");} catch (Exception e) {System.out.println("Task is interrupted!");}return result;}
}
package com.zyf.Future;import java.util.concurrent.*;class MyCallable implements Callable<Object> {private int flag = 0;public MyCallable(int flag) {this.flag = flag;}public String call() throws Exception {if (this.flag == 0) {return "flag = 0";}if (this.flag == 1) {try {while (true) {System.out.println("looping.");Thread.sleep(2000);}} catch (InterruptedException e) {System.out.println("Interrupted");}return "false";} else {throw new Exception("Bad flag value!");}}}public class FutureGetBlock {public static void main(String[] args) {// 定义3个Callable类型的任务MyCallable task1 = new MyCallable(0);MyCallable task2 = new MyCallable(1);MyCallable task3 = new MyCallable(2);// 创建一个执行任务的服务ExecutorService es = Executors.newFixedThreadPool(3);try {// 提交并执行任务,任务启动时返回了一个Future对象,// 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作Future<?> future1 = es.submit(task1);// 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行System.out.println("task1: " + future1.get());Future<?> future2 = es.submit(task2);// 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环Thread.sleep(5000);System.out.println("task2 cancel: " + future2.cancel(true));// 获取第三个任务的输出,因为执行第三个任务会引起异常// 所以下面的语句将引起异常的抛出Future<?> future3 = es.submit(task3);System.out.println("task3: " + future3.get());} catch (Exception e) {System.out.println(e.toString());}// 停止任务执行服务es.shutdownNow();}}
3. Future实现类
3.1 FutureTask
FutureTask是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V> {/*** Sets this Future to the result of its computation* unless it has been cancelled.*/void run();
}
另外它还可以包装Runnable和Callable<V>
public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW; // ensure visibility of callable}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW; // ensure visibility of callable}
可以看到,Runnable会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :
public static <T> Callable<T> callable(Runnable task, T result) {if (task == null)throw new NullPointerException();return new RunnableAdapter<T>(task, result);}
/*** A callable that runs given task and returns given result*/
static final class RunnableAdapter<T> implements Callable<T> {final Runnable task;final T result;RunnableAdapter(Runnable task, T result) {this.task = task;this.result = result;}public T call() {task.run();return result;}}
由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。见下面两个例子:
package com.zyf.Future;import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class FutureTaskDemo {public static void main(String[] args) {Callable<Integer> callable = new Callable<Integer>() {public Integer call() throws Exception {return new Random().nextInt(100);}};FutureTask<Integer> future = new FutureTask<Integer>(callable);new Thread(future).start();try {Thread.sleep(1000);// 可能做一些事情int result = future.get();System.out.println(result);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}
package com.zyf.Future;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;public class FutureTaskDemo2 {static ExecutorService mExecutor = Executors.newSingleThreadExecutor();public static void main(String[] args) {futureDemo();}static void futureDemo() {try {/*** 提交runnable则没有返回值, future没有数据*/Future<?> future = mExecutor.submit(new Runnable() {@Overridepublic void run() {fibc(20);}});System.out.println("future result from runnable : " + future.get());/*** 提交Callable, 有返回值, future中能够获取返回值*/Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {return fibc(20);}});System.out.println("future result from callable : " + result2.get());/*** FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,* 另外它还可以包装Runnable(实际上会转换为Callable)和Callable* <V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行* ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。*/FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {return fibc(20);}});// 提交futureTaskmExecutor.submit(futureTask);System.out.println("future result from futureTask : " + futureTask.get());mExecutor.shutdown();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}/*** 效率底下的斐波那契数列, 耗时的操作* * @param num* @return*/static int fibc(int num) {if (num == 0) {return 0;}if (num == 1) {return 1;}return fibc(num - 1) + fibc(num - 2);}}
如果要执行多个带返回值的任务,并取得多个返回值,两种方法:
1.先创建一个装Future类型的集合,用Executor提交的任务返回值添加到集合中,最后便利集合取出数据。
这时候,submit的task不一定是按照加入自己维护的list顺序完成的。从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住。
如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。
所以jdk1.8增加了Future接口的另外一个实现类CompletionService
2.CompletionService相当于Executor加上BlockingQueue,使用场景为当子线程并发了一系列的任务以后,主线程需要实时地取回子线程任务的返回值并同时顺序地处理这些返回值,谁先返回就先处理谁。
而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。
所以,先完成的必定先被取出。这样就减少了不必要的等待时间。
Callable接口、Runable接口、Future接口相关推荐
- 【Android 异步操作】FutureTask 分析 ( Future 接口解析 | Runnable 接口解析 | Callable 接口解析 )
文章目录 一.Future 接口 1.Future 接口简介 2.取消任务方法 3.Future 接口源码注释 二.Callable 接口 三.Runnable 接口 上一篇博客 [Android 异 ...
- Callable和Future接口的实现
一.Callable和Future Callable接口定义了一个call方法可以作为线程的执行体,但call方法比run方法更强大: call方法可以有返回值 call方法可以申明抛出异常 Call ...
- Callable 和 Future接口 学习
* Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务. * Callable和Runnable有几点不同: * (1)C ...
- Java并发编程-Executor框架之Callable和Future接口
在上一篇文章中我们已经了解了Executor框架进行线程管理,这篇文章将学习Executor框架的另一个特性,我们知道执行Runnable任务是没有返回值得,但Executor可以运行并发任务并获得返 ...
- Java8 - Future 接口
文章目录 Pre 并行 VS 并发 Future接口 使用 Future 以异步的方式执行一个耗时的操作 Future接口的局限性 Pre 并不希望因为等待某些服务的响应,阻塞应用程序的运行,浪费CP ...
- Java基础知识强化之网络编程笔记25:Android网络通信之 Future接口介绍(Java程序执行超时)...
1. Future接口简介 在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现. Future接口是Java标准API ...
- 以两种异步模型应用案例,深度解析Future接口
摘要:本文以实际案例的形式分析了两种异步模型,并从源码角度深度解析Future接口和FutureTask类. 本文分享自华为云社区<[精通高并发系列]两种异步模型与深度解析Future接口(一) ...
- java future接口_java Future 接口介绍
在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现. Future接口是Java标准API的一部分,在java.uti ...
- Future 接口介绍
2019独角兽企业重金招聘Python工程师标准>>> Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务.期间我自己可以去做任何想做的 ...
最新文章
- @RenderBody、@RenderSection、@RenderPage、Html.RenderPartial、Html.RenderAction的作用和区别...
- 如何做好一条0~2岁的产品狗
- phpcms URL修改
- 程序猿生存指南-38 枯木逢春
- MySQL默认INFORMATION_SCHEMA,MySQL,TEST三个数据库用途(转)
- python中利用itchat实现自动回复
- 图片底下配的文字叫什么_PPT排版狂想篇 | 如何用一张图片搞定30种排版
- 持续集成、持续交付、持续部署(转载)
- android 上下文菜单详解
- 《烈烈先秦》9、世界奇迹的缔造者——全才冤臣蒙恬
- Python基础知识——字符串:format() 字符串的格式化
- RationalDMIS 2020 叶片检测 -快速定义叶片截面线方法
- 练习:根据车牌信息,统计各省车牌持有量
- 腾讯主机安全“猎刃计划”发布,WebShell挑战赛再燃起,PHPer燥起来
- Canvas 绘制安卓机器人
- 力扣比赛 5454. 统计全 1 子矩形
- 结构方程模型(SEM)定义及应用【免费教程】
- 论文阅读笔记:vTPM
- PowerQuery(导入数据,行操作,列操作,提取与转换,删除重复项,删除错误)
- 如何推进中小学STEM教育课程开发和实施
热门文章
- 解决MSDN安装正常,却无法访问。
- 诗与远方:无题(十四)
- Android之使用MediaPlayer和SurfaceView组件播放一个简单的视频
- SpringBoot使用ControllerAdvice和ExceptionHandler进行统一异常处理
- Java 面向对象:重写的理解
- java.sql.SQLException: Parameter index out of range (5 > number of parameters, which is 4).
- mysql 备份_shell脚本实现MySQL全量备份+异地备份
- python网页提交表单_用Python的urllib库提交WEB表单
- Oracle在JavaOne上宣布Java EE 8将会延期至2017年底
- javascript 面试题之一