多线程
正常来说,由一个线程串行执行的程序,可以通过多线程的方式进行拆解
其中单线程程序可以分为两种:
- IO密集型
- 计算密集型
我们使用多线程编程,主要是为了充分发挥当前多核PCU的计算能力,使并发变为并行。
在程序间没有相互依赖关系的情况下,会极大提高程序的执行效率。并且会随着CPU核心的提升,理论上效率会越来越高。
但现实情况并非理想,很多程序中的步骤都是相互依赖的,即A依赖B,B依赖C,C依赖D。需要考虑 一致性成本的话,并发执行的效率会大大折扣,会随着CPU核数的提升而降低。
反应式编程
反应式编程,这是一个新的概念,不同于响应式编程,函数式。是一种基于函数式编程非阻塞方式来处理数据流的。
简单的,对于Java来说,可以理解为非阻塞的基于时间流的编程范式。
它的兴起,与
Java的绿色线程,Event-loop
Future、Promise(ES6)
Rx系列
Actor模型(基于消息传递)
都有很大的关系
反应式编程的宣言:
- responsive(响应式的)
- resilient (回弹)
- elastic (可伸缩)
- message-driven(消息驱动)
这是一个由三个大公司Pivotal、Netflix等组成的小组联合声明的
上图说话:
小疑问:
在JDK有了Future之后为什么还要有CompletableFuture?
当然是因为Future不够强大,虽然应用Future模式能实现非阻塞编程,但线程间的通讯等操作还是太不方便,所有才有了组合式异步编程CompletableFuture API 的出现。
Reactive Programming
再说反应式编程,可以理解为由一下几个部分组成:
- Observerable + SubScriber + SubScription
- Functional Programming
- BackPressure
- Lazy
Observerable :可观察者,SubScriber 订阅者, SubScription 订阅。
Functional Programming:函数式编程,函数为第一公民,无副作用 不可变 幂等性
BackPressure:回压。生产者向消费者生产数据时,消费者可根据自己消费能力的快慢,回压给生产者,让生产者调节生产速度。
Lazy:就是懒加载,只有真正使用的时候才会触发加载。
Spring WebFlux
再来看下Spring官网对Reactive的介绍
技术栈区别:
可以看出,Spring产品提供了两个并行堆栈。一种基于带有Spring MVC和Spring Data结构的Servlet API。另一个是完全响应式堆栈,它利用了Spring WebFlux和Spring Data的响应式存储库。在这两种情况下,Spring Security都为两个堆栈提供了本机支持。
下面通过手写一个WebFlux组件的Demo来了解一下
第一步:
可以通过IDEA初始化工程,或者通过官网页面初始化。(我用的后者)
地址
https://start.spring.io/
这里注意选择web组件时,选择Spring Reactive Web
第二步:
导入工程,开始写代码。写法与Spring MVC差不多,只不过API变了,先手写个“Hello World”。
第三步:测试走起
启动,可以看出是用的Netty,端口号是8080
浏览器访问
总结:
两个常见Class区别
Mono:有或者没有
Flux:有0个或者多个
Spring WebFlux的Overflow策略
- ignore。直接忽略
- Error。直接报错
- Drop。删除掉之前的
- Lastest。直接用最新的
- Buffer。使用缓存,等空闲了在处理
Spring WebFlux几个重要的函数
publishOn()
只要发布者调用了publishOn方法就会使用新的线程,当然如果指定了scheduler的话就会用指定线程池中的线程
subscribeOn()
订阅者订阅的时候使用subscribeOn方法来指定使用哪个线程池或者说具体的线程
parallel()
使用parallel方法时就是告诉程序在处理flux时使用多线程,并且默认的线程数就是CPU的核数。(这个地方注意,为什么不适用更多的线程,更多的线程效率不就更高吗,自己思考)
runOn()
就是parallel之后运行与某个线程池上
后记
对Web Flux的实践暂时太少,希望能在后面更多的实践有更多的体会。