JDK  实现

public class FutureTest { 

    public static void main(String[] args) throws Exception {
ExecutorService es = Executors.newFixedThreadPool(10);
Future<Integer> f = es.submit(() ->{
Thread.sleep(5000);
// 结果
return 100;
}); Integer result = f.get();
System.out.println(result); // 也可以轮询等结束
// while (f.isDone()) {
// System.out.println(result);
// }
} }

虽然这些方法提供了异步执行任务的能力,但是对于结果的获取却还是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。
阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的CPU资源,而且也不能及时的得到计算结果。
Java的一些框架,
Netty,自己扩展了Java的 Future 接口,提供了 addListener 等多个扩展方法。
Google的guava也提供了通用的扩展Future:ListenableFuture 、 SettableFuture 以及辅助类 Futures 等,方便异步编程。
Java 在JDK1.8 这个版本中增加了一个能力更强的Future类:CompletableFuture 。它提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果。下面来看看这几种方式。

Netty-Future

引入Maven依赖:

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.50.Final</version>
</dependency>

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.7</version>
</dependency>
package com.vipsoft;

import cn.hutool.core.date.DateUtil;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch; public class FutureTest { public static void main(String[] args) throws InterruptedException {
EventExecutorGroup group = new DefaultEventExecutorGroup(4);
System.out.println("开始:" + DateUtil.now()); Future<Integer> f = group.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("开始耗时计算:" + DateUtil.now());
Thread.sleep(5000);
System.out.println("结束耗时计算:" + DateUtil.now());
int a = 0;
int b = 1;
int c = b / a;
return 100;
}
}); //通过监听,待线程结束后,自动触发,避免了主线程 的阻塞和等待
f.addListener(new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> objectFuture) throws Exception {
System.out.println("计算结果:" + objectFuture.get());
}
}); System.out.println("结束:" + DateUtil.now());
// 不让守护线程退出
new CountDownLatch(1).await();
} }

在Listener添加成功之后,会立即检查状态,如果任务已经完成立刻进行回调,通过监听,待线程结束后,自动触发,避免了主线程 的阻塞和等待

Guava-Future

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.7</version>
</dependency>
package com.vipsoft;

import cn.hutool.core.date.DateUtil;
import com.google.common.util.concurrent.*; import javax.annotation.Nullable;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class FutureTest { public static void main(String[] args) throws InterruptedException {
System.out.println("开始:" + DateUtil.now()); ExecutorService executorService = Executors.newFixedThreadPool(10);
ListeningExecutorService service = MoreExecutors.listeningDecorator(executorService);
ListenableFuture<Integer> future = service.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("开始耗时计算:" + DateUtil.now());
Thread.sleep(5000);
System.out.println("结束耗时计算:" + DateUtil.now());
return 100;
}
}); //增加回调函数,一般用于不在乎执行结果的地方
future.addListener(new Runnable() {
@Override
public void run() {
System.out.println("调用成功--不关心结果");
}
}, executorService); //通过addCallback 获得结果
Futures.addCallback(future, new FutureCallback<Integer>() {
@Override
public void onSuccess(@Nullable Integer result) {
System.out.println("成功,计算结果:" + result);
} @Override
public void onFailure(Throwable t) {
System.out.println("失败");
}
}, executorService); System.out.println("结束:" + DateUtil.now());
new CountDownLatch(1).await();
}
}

CompletableFuture 使用

package com.vipsoft;

import cn.hutool.core.date.DateUtil;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch; public class FutureTest { public static void main(String[] args) throws InterruptedException {
System.out.println("开始:" + DateUtil.now());
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("开始耗时计算:" + DateUtil.now());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束耗时计算:" + DateUtil.now());
return 100;
});
//使用 thenCompose 或者 thenComposeAsync 等方法可以实现回调的回调,且写出来的方法易于维护。
completableFuture = completableFuture.thenCompose(i -> {
return CompletableFuture.supplyAsync(() -> {
System.out.println("在回调的回调中执行耗时操作...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return i + 200;
});
});
completableFuture.whenComplete((result, e) -> {
System.out.println("回调结果:" + result);
}); System.out.println("结束:" + DateUtil.now());
new CountDownLatch(1).await();
}
}

JDK1.8 已经提供了一种更为高级的回调方式:CompletableFuture,不需要引入任何第三方的依赖,为Future模式增加回调功能就不需要阻塞等待结果的返回并且不需要消耗无谓的CPU资源去轮询处理状态,JDK8之前使用Netty或者Guava提供的工具类,JDK8之后则可以使用自带的 CompletableFuture 类。Future 有两种模式:将来式和回调式。而回调式会出现回调地狱的问题,由此衍生出了 Promise 模式来解决这个问题。这才是 Future 模式和 Promise 模式的相关性。

多种方式实现 Future 回调返回结果的更多相关文章

  1. PDO多种方式取得查询结果

    PDO多种方式取得查询结果 01 December 2009 1:26 Tuesday by Sjolzy PDO最大的特点之一是它的灵活性,本节将介绍如何取得查询结果,包括: 数组(数值或关联数组) ...

  2. 11月18日内容总结——同步、异步与阻塞、非阻塞的概念、创建进程的多种方式及multiprocessing模块、进程间的数据隔离和IPC机制(队列)、生产者消费者模型、守护进程、僵尸进程、孤儿进程和多进程错乱问题

    目录 一.同步与异步 同步 异步 二.阻塞与非阻塞 阻塞 非阻塞 三.综合使用 1.同步阻塞: 2.同步非阻塞: 3.异步阻塞: 4.异步非阻塞: 四.创建进程的多种方式 进程的创建 multipro ...

  3. Spring学习总结(一)——Spring实现IoC的多种方式

    控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法.没有IoC的程序中我们使用面向对象编程对象的创 ...

  4. sql语句分页多种方式ROW_NUMBER()OVER

    sql语句分页多种方式ROW_NUMBER()OVER 摘自: http://www.cnblogs.com/CodingArt/articles/1692468.html 方式一 select to ...

  5. JavaScript中判断为整数的多种方式

    之前记录过JavaScript中判断为数字类型的多种方式,这篇看看如何判断为整数类型(Integer). JavaScript中不区分整数和浮点数,所有数字内部都采用64位浮点格式表示,和Java的d ...

  6. 使用多种方式实现遍历HashMap

    今天讲解的主要是使用多种方式来实现遍历HashMap取出Key和value,首先在java中如果想让一个集合能够用for增强来实现迭代,那么此接口或类必须实现Iterable接口,那么Iterable ...

  7. Jquery Validate 表单验证的多种方式

    ASP.NET MVC Jquery Validate 表单验证的多种方式 在我们日常开发过程中,前端的表单验证很重要,如果这块处理不当,会出现很多bug .但是如果处理的好,不仅bug会很少,用户体 ...

  8. Spring实现Ioc的多种方式--控制反转、依赖注入、xml配置的方式实现IoC、对象作用域

    Spring实现Ioc的多种方式 一.IoC基础 1.1.概念: 1.IoC 控制反转(Inversion of Control) IoC是一种设计思想. 2.DI 依赖注入 依赖注入是实现IoC的一 ...

  9. 在 ASP.NET 网页中不经过回发而以编程方式实现客户端回调

    在 ASP.NET 网页的默认模型中,用户会与页交互,单击按钮或执行导致回发的一些其他操作.此时将重新创建页及其控件,并在服务器上运行页代码,且新版本的页被呈现到浏览器.但是,在有些情况下,需要从客户 ...

  10. ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客

    原文:ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客 版权声明:本文为starfd原创文章,转载请标明出处. https://blog.c ...

随机推荐

  1. include 0。0

    参考好文 php://filter的各种过滤器_php://filter过滤器种类-CSDN博客 打开页面是一段php代码 可以知道flag在flag.php文件里面,然后执行没有结果,就只能用文件读 ...

  2. 微信小程序动态生成表单来啦!你再也不需要手写表单了!

    dc-vant-form 由于我们在小程序上涉及到数据采集业务,需要经常使用表单,微信小程序的表单使用起来非常麻烦,数据和表单是分离的,每个输入框都需要做数据处理才能实现响应式数据,所以我开发了dc- ...

  3. C语言输入若干个正整数(输入-1为结束标志),要求按输入数据的逆序建立单链表并输出。

    /* 开发者:慢蜗牛 开发时间:2020.6.11 程序功能:逆序建立链表,顺序输出 */ #include<stdio.h> #include<malloc.h> #defi ...

  4. 小米二面:Redis 如何保证数据不丢失?

    前段时间表妹收到了小米秋招补录的面试邀请,一面还算顺利,很快就通过了,但在看二面面试录屏的时候,我发现了一个问题,回答的不是很好,也就是我们今天要聊的这个问题:Redis 如何保证数据不丢失? 很多人 ...

  5. cookie和session的区别?一文讲透

    一.问题 cookie和session的区别? 二.回答 1.总结如下- cookie: - cookie存储于客户端本地,即浏览器缓存 - cookie存储着sessionId,作为后台sessio ...

  6. 通过.NET Core+Vue3 实现SignalR即时通讯功能

    .NET Core 和 Vue3 结合使用 SignalR 可以实现强大的实时通讯功能,允许实时双向通信.在这个示例中,我们将详细说明如何创建一个简单的聊天应用程序,演示如何使用 .NET Core ...

  7. liunx二进制包安装5.6MySQL数据库

    官网下载对应的二进制版本安装包 https://downloads.mysql.com/archives/community/ # 解压二进制压缩包 [root@localhost ~]# wget ...

  8. 5分钟安装Kubernetes+带你轻松安装istio服务网格指南

    上次我跟大家简单介绍了一下Kubernetes的各个组件及其含义,本期本来计划带领大家一起学习一些常用命令,但我认为这种方式可能无法达到学习的效果.有可能你们会直接忘记,甚至可能没有兴趣去学.我也理解 ...

  9. Git恢复删除的文件,一行命令就可以啦~

    情况一:删除或者修改了某个文件,但是没有add # 单个 git checkout filename # 多个 git checkout . 情况二:删除或者修改了某个文件,已经add,但是没有com ...

  10. CH395+EMQX实现MQTT应用(Windows系统)

    目录: 1.MQTT协议 1.1简介 1.2特性 1.3实现方式 1.4数据包结构 2.EMQX具体操作步骤 3.代码说明 4.工程链接 MQTT协议 1.MQTT简介 MQTT是一种基于 发布/订阅 ...