java响应式编程有几种方式_什么是响应式编程,Java 如何实现
什么是响应式编程,Java 如何实现
我们这里用通过唯一 id 获取知乎的某个回答作为例子,首先我们先明确下,一次HTTP请求到服务器上处理完之后,将响应写回这次请求的连接,就是完成这次请求了,如下:
public void request(Connection connection, HttpRequest request) {
//处理request,省略代码
connection.write(response);//完成响应
}
假设获取回答需要调用两个接口,获取评论数量还有获取回答信息,传统的代码可能会这么去写:
//获取评论数量
public void getCommentCount(Connection connection, HttpRequest request) {
Integer commentCount = null;
try {
//从缓存获取评论数量,阻塞IO
commentCount = getCommnetCountFromCache(id);
} catch(Exception e) {
try {
//缓存获取失败就从数据库中获取,阻塞IO
commentCount = getVoteCountFromDB(id);
} catch(Exception ex) {
}
}
connection.write(commentCount);
}
//获取回答
public void getAnswer(Connection connection, HttpRequest request) {
//获取点赞数量
Integer voteCount = null;
try {
//从缓存获取点赞数量,阻塞IO
voteCount = getVoteCountFromCache(id);
} catch(Exception e) {
try {
//缓存获取失败就从数据库中获取,阻塞IO
voteCount = getVoteCountFromDB(id);
} catch(Exception ex) {
}
}
//从数据库获取回答信息,阻塞IO
Answer answer = getAnswerFromDB(id);
//拼装Response
ResultVO response = new ResultVO();
if (voteCount != null) {
response.setVoteCount(voteCount);
}
if (answer != null) {
response.setAnswer(answer);
}
connection.write(response);//完成响应
}
在这种实现下,你的进程只需要一个线程池,承载了所有请求。这种实现下,有两个弊端:
线程池 IO 阻塞,导致某个存储变慢或者缓存击穿的话,所有服务都堵住了。假设现在评论缓存突然挂了,全都访问数据库,导致请求变慢。由于线程需要等待 IO 响应,导致唯一一个线程池被堆满,无法处理获取回答的请求。
对于获取回答信息,获取点赞数量其实和获取回答信息是可以并发进行的。不用非得先获取点赞数量之后再获取回答信息。
现在,NIO 非阻塞 IO 很普及了,有了非阻塞 IO,我们可以通过响应式编程,来让我们的线程不会阻塞,而是一直在处理请求。这是如何实现的呢
传统的 BIO,是线程将数据写入 Connection 之后,当前线程进入 Block 状态,直到响应返回,之后接着做响应返回后的动作。NIO 则是线程将数据写入 Connection 之后,将响应返回后需要做的事情以及参数缓存到一个地方之后,直接返回。在有响应返回后,NIO 的 Selector 的 Read 事件会是 Ready 状态,扫描 Selector 事件的线程,会告诉你的线程池数据好了,然后线程池中的某个线程,拿出刚刚缓存的要做的事情还有参数,继续处理。
那么,怎样实现缓存响应返回后需要做的事情以及参数的呢Java 本身提供了两种接口,一个是基于回调的 Callback 接口(Java 8 引入的各种Functional Interface),一种是 Future 框架。
基于 Callback 的实现:
//获取回答
public void getAnswer(Connection connection, HttpRequest request) {
ResultVO resultVO = new ResultVO();
getVoteCountFromCache(id, (count, throwable) - {
//异常不为null则为获取失败
if (throwable != null) {
//读取缓存失败就从数据库获取
getVoteCountFromDB(id, (count2, throwable2) - {
if (throwable2 == null) {
resultVO.setVoteCount(voteCount);
}
//从数据库读取回答信息
getAnswerFromDB(id, (answer, throwable3) - {
if (throwable3 == null) {
resultVO.setAnswer(answer);
connection.write(resultVO);
} else {
connection.write(throwable3);
}
});
});
} else {
//获取成功,设置voteCount
resultVO.setVoteCount(voteCount);
//从数据库读取回答信息
getAnswerFromDB(id, (answer, throwable2) - {
if (throwable2 == null) {
resultVO.setAnswer(answer);
//返回响应
connection.write(resultVO);
} else {
//返回错误响应
connection.write(throwable2);
}
});
}
});
}
可以看出,随着调用层级的加深,callback 层级越来越深,越来越难写,而且啰嗦的代码很多。并且,基于 CallBack 想实现获取点赞数量其实和获取回答信息并发是很难写的,这里还是先获取点赞数量之后再获取回答信息。
那么基于 Future 呢我们用 Java 8 之后引入的 CompletableFuture 来试着实现下。
//获取回答
public void getAnswer(Connection connection, HttpRequest request) {
ResultVO resultVO = new ResultVO();
//所有的异步任务都执行完之后要做的事情
CompletableFuture.allOf(
getVoteCountFromCache(id)
//发生异常,从数据库读取
.exceptionallyComposeAsync(throwable - getVoteCountFromDB(id))
//读取完之后,设置VoteCount
.thenAccept(voteCount - {
resultVO.setVoteCount(voteCount);
}),
getAnswerFromDB(id).thenAccept(answer - {
resultVO.setAnswer(answer);
})
).exceptionallyAsync(throwable - {
connection.write(throwable);
}).thenRun(() - {
connection.write(resultVO);
});
}
这种实现就看上去简单多了,并且读取点赞数量还有读取回答内容是同时进行的。
Project Reactor 在 Completableuture 这种实现的基础上,增加了更多的组合方式以及更完善的异常处理机制,以及面对背压时候的处理机制,还有重试机制。
每日一刷,轻松提升技术,斩获各种offer:
什么是响应式编程,Java 如何实现 相关文章
什么原因才导致 select * 效率低下的
面试官:“小陈,说一下你常用的SQL优化方式吧。”陈小哈:“那很多啊,比如不要用SELECT *,查询效率低。巴拉巴拉...”面试官:“为什么不要用SELECT * 它在哪些情况下效率低呢”陈小哈:“SELECT * 它好像比写指定列名多一次全表查询吧,还多查了一些无用
linux配置DNS主从配置
DNS主从搭建 什么是DNS DNS( Domain Name System)是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,使用的是UDP协议的53号端口,它用于TCP/IP网络,它所提供的服务是用来将主机名和域名转换为IP地址的工作。DNS就是这样的一位
Java(4) | 匿名对象
# 什么是匿名对象 匿名对象没有名字和赋值运算 new 类名称(); 创建对象的标准格式: 类名称 对象名 = new 类名称(); # 注意事项 匿名对象只能使用一次 所以如果确定某个对象只是用一次,则可以使用匿名对象 # 代码演示 package com.leerep.javabase.anonymou
MQ学习1
MQ(bilibili) MQ和RabbitMQ基础 1 什么是MQ ?举例:用户注册 ?原来: 用户--短信服务--邮件服务--数据库 ?多线程:用户--短信(1秒) ?用户--邮件(1秒) ?用户--数据库(1秒) ?消息队列:用户--数据库(1秒) ?用户--消息队列(MQ)(0.5秒) ?消息队列(MQ)--短信 ?消
Day8
1什么是构造函数 构造函数是bai一种特殊的成员函数du,它主要用于为对象分配存zhi储空间,对数据成dao员进zhuan行初始化.构造函数shu具有一些特殊的性质: (1)构造函数的名字必须与类同名; (2)构造函数没有返回类型,它可以带参数,也可以不带参数; (3)声明类对象
关于Java注解(annotation)的简单理解
一、什么是注解 从 JDK5 开始,Java增加对元数据的支持,也就是注解。简单理解就是代码里的特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。 二、为什么要使用注解 注解可以被其他程序(比如:
RestHighLevelClient的使用
是什么 es官网推荐的es客户端组件RestHighLevelClient, 其封装了操作es的crud方法,底层原理就是模拟各种es需要的请求,如put,post,delete,get等方式 使用步骤 1.引入pom依赖 2.application.yml配置ES 3.查询 // 构建查询参数SearchSourceBuilder search
makefile终极奥义
什么是makefile? 或许很多 Winodws 的程序员都不知道这个东西,因为那些 Windows 的 IDE 都为你做了这个工作,但是一个好的和 professional 的程序员, makefile 还是要懂。这就好像现在有这么多的 HTML 的编辑器,但如果你想成为一个专业人士,你还是要了
HTTP请求响应过程
HTTP请求 HTTP是超文本传输协议,其定义了客户端与服务器端之间文本传输的规范。HTTP默认使用80端口,这个端口指的是服务端的端口,而客户端使用的端口是动态分配的。当我们没有指定端口访问时,浏览器会默认帮我们添加80端口。我们也可以自己指定访问端口如
你不知道的 Proxy
在从观察者模式到响应式的设计原理这篇文章中,阿宝哥介绍了 observer-util 这个库如何使用 Proxy 来实现响应式。而对于 vue-next 项目中的 @vue/reactivity 模块,也是利用 Proxy 来实现响应式。因此,如果你要学习 @vue/reactivity 模块的话,就需要先掌握
java响应式编程有几种方式_什么是响应式编程,Java 如何实现相关推荐
- Java反射之创建对象的四种方式
Java反射之创建对象的四种方式 1.使用new关键字 2.使用Java反射机制,反射构造器 3.使用克隆方式创建对象Cloneable 4.使用序列化Serializable 1.使用Java反射机 ...
- Java异步非阻塞编程的几种方式
简介: Java异步非阻塞编程的几种方式 一. 从一个同步的Http调用说起 一个很简单的业务逻辑,其他后端服务提供了一个接口,我们需要通过接口调用,获取到响应的数据. 逆地理接口:通过经纬度获取这个 ...
- 返回ajax有几种方式,java ajax返回 Json 的 几种方式
方式 1. : 自写代码转 Json 需要 HttpHttpServletRequest request HttpServletResponse response 后台 : @RequestMap ...
- 【转】java调用http接口的几种方式总结
java调用http接口的几种方式总结 本文参考: https://blog.csdn.net/fightingXia/article/details/71775516 https://www.cnb ...
- java读取XML文件的四种方式
java读取XML文件的四种方式 Xml代码 <?xml version="1.0" encoding="GB2312"?> <RESULT& ...
- java直接调用复制文件,java中文件复制的4种方式,java文件的复制
java中文件复制的4种方式,java文件的复制 今天一个同事问我文件复制的问题,他一个100M的文件复制的指定目录下竟然成了1G多,吓我一跳,后来看了他的代码发现是自己通过字节流复制的,定义的字节数 ...
- Java中HashMap遍历的两种方式
第一种: Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Ma ...
- Java转JSON串的几种方式
以下总结一下java转JSON串的几种方式: 1.将java对象转成json串 2.通过JSONObject生成json串 3.通过json字符串生成json串 代码通过阿里的fastjson包实现. ...
- JAVA中集合输出的四种方式
在JAVA中Collection输出有四种方式,分别如下: 一) Iterator输出. 该方式适用于Collection的所有子类. public class Hello {public stati ...
最新文章
- 网络推广营销浅析网站在优化中流量突然减少了是为什么?
- sas university edition在ubuntu中的使用
- 铺地毯(矩形的交+前后缀矩形交)
- apache.camel_带有Spring Boot 2支持的Apache Camel 2.22发布
- linux CentOS7最小化安装环境静默安装Oracle11GR2数据库(安装依赖包_03)
- 微软为何选择在 Github 上开源 .NET 核心?
- 渗透测试入门2之进入内网
- ai里怎样取消扩展外观_扩展AI:困难的5个原因
- linux环境编程apue和unp,《APUE》和《UNP》文件的编译和使用(转载)
- 汽车销售管理系统 c语言版 课程设计,《汽车销售管理系统 C语言版》.doc
- Networkx参考手册
- 2021-1016-复盘 强势股-风口综合实战
- Edge浏览器运行卡顿怎么办 怎样让Edge浏览器速度更快
- 计算机网络介质图片,存储介质是什么
- Oracle数据库----------------索引
- 有未经处理的异常 0xC00000FD Stack overflow (参数: 0x00000000, 0x00842000)
- java cloud五大神兽_SpringCloud五大神兽之Eureka
- 善用 GOOGLE -- 从入门到精通
- python分析股票MACD指标
- 功能测试中遇到不可重现软件缺陷的解决策略