本文以实际案例的形式分析了两种异步模型,并从源码角度深度解析Future接口和FutureTask类,希望大家踏下心来,打开你的IDE,跟着文章看源码,相信你一定收获不小!
一、两种异步模型在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 + 'http://blog.51cto.com/u_15214399/3230109/\'' + ", taskResult='" + taskResult + 'http://blog.51cto.com/u_15214399/3230109/\'' + '}'; } }创建回调接口的实现类
回调接口的实现类主要用来对任务的返回结果进行相应的业务处理,这里,为了方便演示,只是将结果数据返回。大家需要根据具体的业务场景来做相应的分析和处理。
package io.binghe.concurrent.lab04; /** * @author binghe * @version 1.0.0 * @description 回调函数的实现类 */ public class TaskHandler implements TaskCallable<TaskResult> { @Override public 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接口获取异步结果
免责声明:本站发布的内容(图片、视频和文字)以原创、来自互联网转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:ts@56dr.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
Copyright © 2009-2021 56dr.com. All Rights Reserved. 特网科技 版权所有 珠海市特网科技有限公司 粤ICP备16109289号
域名注册服务机构:阿里云计算有限公司(万网) 域名服务机构:烟台帝思普网络科技有限公司(DNSPod) CDN服务:阿里云计算有限公司 中国互联网举报中心 增值电信业务经营许可证B2