同步OR异步?WebFlux开发真的比Servlet开发要快?顺便再科普下CompletableFuture

在看下文之前,先给大家科普一点基础知识

Runable:线程任务类接口,没有返回值

Callable:与上面的不同就是有返回值

Executor:定义了线程池执行任务的接口,不过只定义了Runable的,也就是execute

ExecutorService:是线程池的规范,像ThreadPoolExecutor就是它的实现类,继承了Executor,并且自己还扩展了对于Callable任务类的执行规范,也就是submit()

Executors:一个工具类,提供了一些有默认配置的线程池,如new FixedThreadPool(int num),其实除了newWorkStealingPool(使用的是ForkJoinPool)外使用的都是ThreadPoolExecutor,包括ScheduledThreadPoolExecutor,定时器线程池,只是队列使用的是
DelayedWorkQueue这种延时阻塞队列.

Future: java对于future模式实现的接口
FutureTask:Future接口的实现类

首先,请大家思考一个问题,异步与同步是什么?区别在哪里?看清楚,这里说的是异步和同步,而不是阻塞与非阻塞(阻塞与非阻塞的区别是在于线程是否被阻塞的概念,也就是碰到一个会阻塞的代码(如IO)你是开启子线程去运行让主线程直接过还是让主线程去阻塞等着).

相比于阻塞和非阻塞这种定义非常清晰直观的观念,同步与异步的概念则非常模糊,在我刚接触NIO与AIO的时候因为网上各种博客的误导以及自己也没有花时间思考其本质(独立思考很重要,不要只是被动接受),导致一度理解为同步和异步的概念是操作系统级别的,也就是这个任务的触发是系统主动通知你(回调)的,还是你在程序里不停的轮询查看是否达到触发条件的.

其实,这只是表面现象,大家想想,程序主动访问和系统通知你,这两个真正的区别在于什么?其实是在于一个是需要我们不停的轮询,不停的人为查看.而另一个则是通过回调函数,也就是由完成任务的事件触发的,不需要我们去人为观察的.这才是同步和异步的区别,同步在某一个点上仍然需要去主动访问我们的任务线程.而异步,则是任务线程自己告诉我们,我们已经完成了.也就是说,它们真正的区别在于,有没有完成任务后的回调函数!

理解到了这个,我们再来说说对于CompletableFuture,首先,此类是java第一个真正的异步编程实现,FutureTask则是同步,原因也很简单,你需要主动去拿FutureTask里的返回值(get()方法),也就顺应了我们上文对于同步的观点,同步是需要我们程序去主动访问我们的任务线程

CompletableFuture则不需要我们主动获取,原因也很简单,CompletableFuture是基于事件驱动的数据处理.也就是说,CompletableFuture可以注册监听器,这样一旦我们的数据处理完成就会自动触发回调

下面是一个小的demo

从打印的信息来分析

1.在我们没有指定线程池的情况下CompletableFuture默认使用的是ForkjoinPool,而ForkjoinPoll的线程则是守护线程,这也就是我为什么要在最后join的原因.(守护线程的生存周期是依赖于前台线程的,也就是说,我主线程运行完了jvm就直接退出而不会管守护线程是否还在执行.)

2.虽然在链式的每一个调用里都指定了异步,整个方法链依然使用的是同一个线程,原因是这些调用都存在依赖关系,所以我一直觉得CompletetableFuture的链式调用挺鸡肋的.但是!虽然在链式调用里方法的运行是串行的,但对于外面调用它的线程来说,它依然是异步的(参考上文对与异步的定义)

上面之所以说CompletableFuture的概念,是因为CompletableFuture其实就是典型的响应式编程风格,为我们下面要说的WebFlux做个铺垫,所以我们下面再来说说WebFlux最大的误区,也就是响应式编程相比于Servlet效率更高,性能更好,响应时间更短

大家都知道,Spring5推出了一个WebFlux开发框架,(使用Netty做的默认服务器,并且不使用Servlet规范),利用Mono(对应单例)和WebFlux(对应多例)

我们看下面这个例子

首先请注意,Mono是Netty提供的实现而非Spring,之后再请大家思考一个过程,当我访问这个代码的时候,会发生什么呢?

Spring会去启动一个线程去处理Mono方法调用链,之后马上返回,看清楚,是启动,都不一定开始运行,可能只是就绪的状态就会返回(这里科普下线程生命周期的一个基础知识,当你启动一个线程后,此线程并非会马上运行,它还需要等待cpu的时间片)

但是!这里马上会返回的意思是处理Request请求的线程马上返回,而Response线程则不会马上响应给客户端,因为Mono线程还需要处理数据呢,而当Mono线程处理数据之后,会通过事件的形式被Response监听到,此时Response拿到数据后返回(此处可以理解为Mono在处理完数据后push给了Response)

Ok,这里大家应该都懂了吧,WebFlux框架在我们程序看来是异步的,但是在客户端响应看来还是同步的(因为我还是需要你返回给我数据我才可以响应给客户端,从某点来说对于客户端的即时响应这种事情,除非是一些后台任务,也就是无关响应内容的任务,否则都是没办法做到异步的),

也正因此,在WebFlux和传统Servlet开发都可以使用多线程的情况下WebFlux框架完全没有比之前Request和Response同步处理快的点,甚至可能会更慢,因为在开启了大量线程的情况下,线程上下文切换是一个很大的开销.要知道,WebFlux开发始终比传统开发要多开一个线程

而且最搞笑的一点是,Spring WebFlux框架的这种做法和Servlet 3(异步处理任务,Request即时返回)殊途同归.所以WebFlux框架比Servlet效率更高,响应更快这种说法不攻自破。

所以结论就是,webflux框架真的只是一种编程风格框架,就跟java8提供的函数式编程框架Stream一样,只能降低而不能提高任何性能,webflux框架能实现的,用其它方式一样能做到。

原文地址:https://www.cnblogs.com/yangfeiORfeiyang/p/9503429.html

时间: 2024-11-09 00:47:54

同步OR异步?WebFlux开发真的比Servlet开发要快?顺便再科普下CompletableFuture的相关文章

初学 Java Web 开发,从 Servlet 开发

1. 基本要求:Java 编程基础 有良好的 Java 语言编程基础,这是必须的,在讨论 Web 开发技术时提了一个 Java 编程基础的问题会被鄙视的. 2. 环境准备 (Eclipse + Tomcat) 选择一个你喜爱的Servlet容器,或者说大一点就是应用服务器,推荐 Tomcat .Resin 或者 Jetty 这些轻量级的产品.这三个产品下载 zip 包解压后就可以用了.如果你不熟悉 Tomcat 的话请不要使用 exe 版本的 Tomcat,那会徒增很多烦恼.也不建议在 Ecli

javaweb 开发总结五-----servlet开发(一)

一 servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术 Sun公司在其API 中提供了一个Servlet接口,用户若想开发一个动态web资源(及开发一个Java程序向浏览器输出数据),需要完成以下2个步骤: 1.编写一个java类,实现servlet接口 2.把开发好的java类部署到web服务器中 按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为servlet 二 Servlet的运行过程 Servlet程序是由web服务

python 37 同步、异步调用

目录 1. 阻塞与非阻塞 2. 同步与异步 2.1 异步调用 2.2 同步调用 2.3 异步调用回收的第一种方式 3. 异步调用+回调函数 3.1 requests模块 3.2 异步调用回收的第二种方式 1. 阻塞与非阻塞 执行的角度: ? 阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起(如遇到io操作).函数只有在得到结果之后才会将阻塞的线程激活. ? 非阻塞:程序没有遇到IO阻塞,或者程序遇到IO,通过某种方式,让CPU强行运行程序. 2. 同步与异步 发布的角度: ? 同步调用:在发

关于Web开发里并发、同步、异步以及事件驱动编程的相关技术

一.开篇语 我的上篇文章<关于如何提供Web服务端并发效率的异步编程技术>又成为了博客园里“编辑推荐”的文章,这是对我写博客很大的鼓励,也许是被推荐的原因很多童鞋在这篇文章里发表了评论,有童鞋说我这篇文章理论化很严重,没有实际代码和具体项目做支撑,这个评论让我有种理论和实践脱节的味道,所以我想在这里谈谈我为什么要写这篇文章的原因,这篇文章是把我前不久学习多线程编程的一个总结. 当我从我书堆里找到所有与多线程开发相关的书籍简单阅读后,我发现了一个问题,在java里开发多线程最强有力的实践就是做服

使用C++11 开发一个半同步半异步线程池

摘自:<深入应用C++11>第九章 实际中,主要有两种方法处理大量的并发任务,一种是一个请求由系统产生一个相应的处理请求的线程(一对一) 另外一种是系统预先生成一些用于处理请求的进程,当请求的任务来临时,先放入同步队列中,分配一个处理请求的进程去处理任务, 线程处理完任务后还可以重用,不会销毁,而是等待下次任务的到来.(一对多的线程池技术) 线程池技术,能避免大量线程的创建和销毁动作,节省资源,对于多核处理器,由于线程被分派配到多个cpu,会提高并行处理的效率. 线程池技术分为半同步半异步线程

java中同步和异步有什么异同?

同步交互:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程: 异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待. 区别:一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式. 哪些情况建议使用同步交互呢?比如银行的转账系统,对数据库的保存操作等等,都会使用同步交互操作,其余情况都优先使用异步交互.

socket阻塞与非阻塞,同步与异步、I/O模型,select与poll、epoll比较

1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步:      所谓同步,就是在c端发出一个功能调用时,在没有得到结果之前,该调用就不返回.也就是必须一件一件事做,等前一件做完了才能做下一件事. 例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事 异步:      异步的概念和同步相对.当c端一个异步过程调用发出后,调

【iOS面试系列-2】多线程中同步、异步和串行、并行之间的逻辑关系(必考,必须掌握)

一.同步.异步和串行.并行 任务串行执行就是每次只有一个任务被执行,任务并发执行就是在同一时间可以有多个任务被执行. 一个同步函数只在完成了它预定的任务后才返回.一个异步函数,刚好相反,会立即返回,预定的任务会完成但不会等它完成.因此,一个异步函数不会阻塞当前线程去执行下一个函数. (来源:http://www.cocoachina.com/industry/20140428/8248.html) 队列分为串行和并行 任务的执行分为同步和异步 -------  队列只是负责任务的调度,而不负责任

(转) Java多线程同步与异步

Java线程 同步与异步 线程池1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成的,有时为了解 决此问题,优先考虑使用局部变量,退而求其次使用同步代码块,出于这样的安全考虑就必须牺牲 系统处理性能,加在多线程并发时资源挣夺最激烈的地方,这就实现了线程的同步机制 同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求 不到,怎么办,A线程只能等待下去