当前位置:网站首页>【高并发】2.8万字的Callable和Future面试知识点总结,看完我直接面进了字节跳动,原谅我有点飘了(中)
【高并发】2.8万字的Callable和Future面试知识点总结,看完我直接面进了字节跳动,原谅我有点飘了(中)
2022-06-29 10:36:00 【华为云】
大家好,我是冰河~~
在Java的多线程编程中,除了Thread类和Runnable接口外,不得不说的就是Callable接口Future接口了。使用继承Thread类或者实现Runnable接口的线程,无法返回最终的执行结果数据,只能等待线程执行完成。此时,如果想要获取线程执行后的返回结果,那么,Callable和Future就派上用场了。
注:文章全程高能,建议收藏,如果文章对你有点帮助,小伙伴们一键三连呀,谢谢啦~~
两种异步模型与深度解析Future接口
两种异步模型
在Java的并发编程中,大体上会分为两种异步编程模型,一类是直接以异步的形式来并行运行其他的任务,不需要返回任务的结果数据。一类是以异步的形式运行其他任务,需要返回结果。
1.无返回结果的异步模型
无返回结果的异步任务,可以直接将任务丢进线程或线程池中运行,此时,无法直接获得任务的执行结果数据,一种方式是可以使用回调方法来获取任务的运行结果。
具体的方案是:定义一个回调接口,并在接口中定义接收任务结果数据的方法,具体逻辑在回调接口的实现类中完成。将回调接口与任务参数一同放进线程或线程池中运行,任务运行后调用接口方法,执行回调接口实现类中的逻辑来处理结果数据。这里,给出一个简单的示例供参考。
- 定义回调接口
package io.binghe.concurrent.lab04;/** * @author binghe * @version 1.0.0 * @description 定义回调接口 */public interface TaskCallable<T> { T callable(T t);}便于接口的通用型,这里为回调接口定义了泛型。
- 定义任务结果数据的封装类
package io.binghe.concurrent.lab04;import java.io.Serializable;/** * @author binghe * @version 1.0.0 * @description 任务执行结果 */public class TaskResult implements Serializable { private static final long serialVersionUID = 8678277072402730062L; /** * 任务状态 */ private Integer taskStatus; /** * 任务消息 */ private String taskMessage; /** * 任务结果数据 */ private String taskResult; //省略getter和setter方法 @Override public String toString() { return "TaskResult{" + "taskStatus=" + taskStatus + ", taskMessage='" + taskMessage + '\'' + ", taskResult='" + taskResult + '\'' + '}'; }}- 创建回调接口的实现类
回调接口的实现类主要用来对任务的返回结果进行相应的业务处理,这里,为了方便演示,只是将结果数据返回。大家需要根据具体的业务场景来做相应的分析和处理。
package io.binghe.concurrent.lab04;/** * @author binghe * @version 1.0.0 * @description 回调函数的实现类 */public class TaskHandler implements TaskCallable<TaskResult> { @Overridepublic TaskResult callable(TaskResult taskResult) {//TODO 拿到结果数据后进一步处理 System.out.println(taskResult.toString()); return taskResult; }}- 创建任务的执行类
任务的执行类是具体执行任务的类,实现Runnable接口,在此类中定义一个回调接口类型的成员变量和一个String类型的任务参数(模拟任务的参数),并在构造方法中注入回调接口和任务参数。在run方法中执行任务,任务完成后将任务的结果数据封装成TaskResult对象,调用回调接口的方法将TaskResult对象传递到回调方法中。
package io.binghe.concurrent.lab04;/** * @author binghe * @version 1.0.0 * @description 任务执行类 */public class TaskExecutor implements Runnable{ private TaskCallable<TaskResult> taskCallable; private String taskParameter; public TaskExecutor(TaskCallable<TaskResult> taskCallable, String taskParameter){ this.taskCallable = taskCallable; this.taskParameter = taskParameter; } @Override public void run() { //TODO 一系列业务逻辑,将结果数据封装成TaskResult对象并返回 TaskResult result = new TaskResult(); result.setTaskStatus(1); result.setTaskMessage(this.taskParameter); result.setTaskResult("异步回调成功"); taskCallable.callable(result); }}到这里,整个大的框架算是完成了,接下来,就是测试看能否获取到异步任务的结果了。
- 异步任务测试类
package io.binghe.concurrent.lab04;/** * @author binghe * @version 1.0.0 * @description 测试回调 */public class TaskCallableTest { public static void main(String[] args){ TaskCallable<TaskResult> taskCallable = new TaskHandler(); TaskExecutor taskExecutor = new TaskExecutor(taskCallable, "测试回调任务"); new Thread(taskExecutor).start(); }}在测试类中,使用Thread类创建一个新的线程,并启动线程运行任务。运行程序最终的接口数据如下所示。
TaskResult{taskStatus=1, taskMessage='测试回调任务', taskResult='异步回调成功'}大家可以细细品味下这种获取异步结果的方式。这里,只是简单的使用了Thread类来创建并启动线程,也可以使用线程池的方式实现。大家可自行实现以线程池的方式通过回调接口获取异步结果。
2.有返回结果的异步模型
尽管使用回调接口能够获取异步任务的结果,但是这种方式使用起来略显复杂。在JDK中提供了可以直接返回异步结果的处理方案。最常用的就是使用Future接口或者其实现类FutureTask来接收任务的返回结果。
- 使用Future接口获取异步结果
使用Future接口往往配合线程池来获取异步执行结果,如下所示。
package io.binghe.concurrent.lab04;import java.util.concurrent.*;/** * @author binghe * @version 1.0.0 * @description 测试Future获取异步结果 */public class FutureTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<String> future = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "测试Future获取异步结果"; } }); System.out.println(future.get()); executorService.shutdown(); }}运行结果如下所示。
测试Future获取异步结果- 使用FutureTask类获取异步结果
FutureTask类既可以结合Thread类使用也可以结合线程池使用,接下来,就看下这两种使用方式。
结合Thread类的使用示例如下所示。
package io.binghe.concurrent.lab04;import java.util.concurrent.*;/** * @author binghe * @version 1.0.0 * @description 测试FutureTask获取异步结果 */public class FutureTaskTest { public static void main(String[] args)throws ExecutionException, InterruptedException{ FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() { @Override public String call() throws Exception { return "测试FutureTask获取异步结果"; } }); new Thread(futureTask).start(); System.out.println(futureTask.get()); }}运行结果如下所示。
测试FutureTask获取异步结果结合线程池的使用示例如下。
package io.binghe.concurrent.lab04;import java.util.concurrent.*;/** * @author binghe * @version 1.0.0 * @description 测试FutureTask获取异步结果 */public class FutureTaskTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() { @Override public String call() throws Exception { return "测试FutureTask获取异步结果"; } }); executorService.execute(futureTask); System.out.println(futureTask.get()); executorService.shutdown(); }}运行结果如下所示。
测试FutureTask获取异步结果可以看到使用Future接口或者FutureTask类来获取异步结果比使用回调接口获取异步结果简单多了。注意:实现异步的方式很多,这里只是用多线程举例。
接下来,就深入分析下Future接口。
边栏推荐
- Getting started with the lvgl Library - Animation
- The first "cyborg" in the world died, and he only transformed himself to "change his life against the sky"
- Data analysis method and Thinking: funnel analysis
- Interview questions of Tencent automation software test of CSDN salary increase secret script (including answers)
- 彻头彻尾理解JVM系列之七:对象在分代模型中的流转过程是怎样的?
- Spark - one to one correspondence between task and partition and detailed explanation of parameters
- (JS) iterator mode
- Self-Improvement! Junior college "counter attack" master of Zhejiang University, 3 SCI, and finally become a doctor of Tsinghua University!
- Online sql to htmltable tool
- Add notification announcements to send notifications to online users
猜你喜欢
![[various * * question series] what are OLTP and OLAP?](/img/3f/48b4108d14d40212f678971c1b62bb.png)
[various * * question series] what are OLTP and OLAP?

Pipeline aggregations pipeline aggregations - parent-2

Qt学习07 Qt中的坐标系统

Modbustcp protocol WiFi wireless learning single channel infrared module (round shell version)

Nature | 全球海洋微生物组的生物合成潜力

(JS) array de duplication

斐波那锲数列与冒泡排序法在C语言中的用法

Evaluation of IP location query interface Ⅱ

CTO专访:合见工软深化产品布局 加速国产EDA技术革新

Qt学习06 窗口部件及窗口类型
随机推荐
Modbus RTU protocol 485 learning 2-way infrared module
Go 单元测试入门实践
如何识别出轮廓准确的长和宽
The former security director of Uber faced fraud allegations and concealed the data leakage event
面试高并发,凉了!!(全程高能,建议收藏)
Specific method and example program of Siemens s7-200smart control stepping motor
Self-Improvement! Junior college "counter attack" master of Zhejiang University, 3 SCI, and finally become a doctor of Tsinghua University!
[daily 3 questions (3)] reformat the phone number
多线程高并发服务器:3个问题
[daily 3 questions (1)] judge the color of a grid on the chess board
Google Earth engine (GEE) - Gedi L2a vector canopy top height (version 2) global ecosystem data set
多线程实现客户端与服务端通信(初级版本)
The necessary operation for those big guys to fly 666 inadvertently at the bash command line terminal
The Chinese Computational Linguistics Conference and the national knowledge atlas and Semantic Computing Conference are in full swing
行业分析| 快对讲,楼宇对讲
How to properly manage temporary files when writing shell scripts
重建中国科研自信——2022最新自然指数排行榜(Nature Index 2022 )公布,中国的研究产出增幅最大...
Encore une fois, le chemin de l'amélioration de redis Cloud
那些大佬经常在bash 命令行终端不经意间666飞起的必备操作
Qt学习15 用户界面与业务逻辑的分离