我们这里用通过唯一 id 获取知乎的某个回答作为例子,首先我们先明确下,一次HTTP请求到服务器上处理完之后,将响应写回这次请求的连接,就是完成这次请求了,如下:

public void request(Connection connection, HttpRequest request) {//处理request,省略代码connection.write(response);//完成响应
}

假设获取回答需要调用两个接口,获取评论数量还有获取回答信息,传统的代码可能会这么去写:

//获取评论数量
public void getCommentCount(Connection connection, HttpRequest request) {Integer commentCount = null;try {//从缓存获取评论数量,阻塞IOcommentCount = getCommnetCountFromCache(id);} catch(Exception e) {try {//缓存获取失败就从数据库中获取,阻塞IOcommentCount = getVoteCountFromDB(id);} catch(Exception ex) {}}connection.write(commentCount);
}//获取回答
public void getAnswer(Connection connection, HttpRequest request) {//获取点赞数量Integer voteCount = null;try {//从缓存获取点赞数量,阻塞IOvoteCount = getVoteCountFromCache(id);} catch(Exception e) {try {//缓存获取失败就从数据库中获取,阻塞IOvoteCount = getVoteCountFromDB(id);} catch(Exception ex) {}}//从数据库获取回答信息,阻塞IOAnswer answer = getAnswerFromDB(id);//拼装ResponseResultVO response = new ResultVO();if (voteCount != null) {response.setVoteCount(voteCount);}if (answer != null) {response.setAnswer(answer);}connection.write(response);//完成响应
}

在这种实现下,你的进程只需要一个线程池,承载了所有请求。这种实现下,有两个弊端:

  1. 线程池 IO 阻塞,导致某个存储变慢或者缓存击穿的话,所有服务都堵住了。假设现在评论缓存突然挂了,全都访问数据库,导致请求变慢。由于线程需要等待 IO 响应,导致唯一一个线程池被堆满,无法处理获取回答的请求。
  2. 对于获取回答信息,获取点赞数量其实和获取回答信息是可以并发进行的。不用非得先获取点赞数量之后再获取回答信息。

现在,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 {//获取成功,设置voteCountresultVO.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 如何实现相关推荐

  1. Android什么是函数,什么是函数响应式编程(JavaAndroid版本)

    什么是函数响应式编程(Java&Android版本) 函数响应式编程(FRP)为解决现代编程问题提供了全新的视角.一旦理解它,可以极大地简化你的项目,特别是处理嵌套回调的异步事件,复杂的列表过 ...

  2. Spring笔记(4):响应式编程、Reactor、WebFlux、Flow

    目录 1.Spring Webflux 介绍 2.响应式编程(Java 实现) 3.响应式编程(Reactor 实现) 4.SpringWebflux 执行流程和核心 API 5.SpringWebf ...

  3. 关于java的响应式编程框架----SpringReactor

    关于Reactor的介绍 Reactor是Spring中的一个子项目是一个基于java的响应式编程框架,此框架是 Pivotal 公司(开发 Spring 等技术的公司)开发的,实现了 Reactiv ...

  4. Java的HTTP服务端响应式编程

    传统的Servlet模型走到了尽头 传统的Java服务器编程遵循的是J2EE的Servlet规范,是一种基于线程的模型:每一次http请求都由一个线程来处理. 线程模型的缺陷在于,每一条线程都要自行处 ...

  5. 阿里专家杜万:Java响应式编程,一文全面解读

    本篇文章来自于2018年12月22日举办的<阿里云栖开发者沙龙-Java技术专场>,杜万专家是该专场第四位演讲的嘉宾,本篇文章是根据杜万专家在<阿里云栖开发者沙龙-Java技术专场& ...

  6. java响应式编程有几种方式_什么是响应式编程,Java 如何实现

    什么是响应式编程,Java 如何实现 我们这里用通过唯一 id 获取知乎的某个回答作为例子,首先我们先明确下,一次HTTP请求到服务器上处理完之后,将响应写回这次请求的连接,就是完成这次请求了,如下: ...

  7. java拥抱响应式编程

    论编程开发语言中的王者,java语言当人不让.我知道很多人开始对我的答案嗤之以鼻,很多会人会反驳道说c,也有人说是python不香吗?如果编程语言看做是篮球界,那么c语言是乔丹,python是贾巴尔, ...

  8. JAVA:响应式编程

    序言 通常我们编写的Java程序,都是一行执行完了,再执行下一行.上一行没有执行完,下一行就不会执行.这种就是指令式编程. 另外一种就是响应式编程,既可以满足当前一行命令还没有执行完时,下一行命令就可 ...

  9. Java:理解java响应式编程

    原文:Understanding reactive programming in Java https://nullbeans.com/understanding-reactive-programmi ...

最新文章

  1. 重大事故!线上系统频繁卡死,凶手竟然是 Full GC ?
  2. C# 多线程參数传递
  3. linux内存占满但是无进程,为什么TOP看不出真实的内存占用情况?
  4. CentOS7 FTP安装与配置
  5. tensorflow LSTM:张量变形,5维变4维,4维变5维
  6. F - Substrings(一些函数的运用)
  7. lIUNX如何加载U盘,光盘
  8. 从零开始Android游戏编程(第二版) 第十章 游戏循环的设计
  9. 超链接小点html,html超链接取消鼠标点指显示小手
  10. 微信小程序超市购物+后台管理系统|前后分离VUE
  11. 搜狗实验室新闻数据文本分类深度学习案例 ———Tensorflow+CNN深度学习全流程(上)
  12. Centos7安装elasticsearch7.14.0遇到问题(无法远程访问;内存小;bootstrap checks failed)
  13. 国王游戏——c++实现
  14. Android编程权威指南第三版 第31章
  15. python打印九九乘法口诀_PYTHON如何打印九九乘法表
  16. 内燃机 vs 外燃机
  17. 网站分析实战——如何以数据驱动决策,提升网站价值(大数据时代的分析利器)
  18. 油价小程序开发 - 手把手教你写小程序(适合初学者)
  19. H5页面苹果手机点击输入框输入内容时 页面自动放大
  20. VMWare安装Kali Linux(4-3)

热门文章

  1. ios12.3beta2_如何回滚到iOS 11(如果您使用的是iOS 12 Beta)
  2. React Native 集成极光推送 jpush-react-native
  3. 【CSS】笔记3-三大样式、盒子模型、PS、圆角、阴影
  4. 液晶屏背光板的分类及知识点
  5. Hulu全球研发副总裁诸葛越谈人工智能
  6. 强哥语录摘抄(郑强教授)
  7. python实训总结万能版3000字_万能实习报告论文范文3000字
  8. 127.0.0.1:3000端口已被占用
  9. 四则运算java_小学生四则运算JAVA
  10. 化工企业安全生产管理监控预警系统软件