生活在这个世界上,我们必须承认,一切都在运动中变化,没有什么是静止的。不仅因为这句话出自马克思主义哲学的唯物辩证法,更因为它是真实的。这种变化描述如下。分工的出现和合作一定是已经买房或者最终会买房。自然离不开装修,那我们就从装修的话题说起吧。假设有一个从事装修的人,名叫小王。小王做得特别好,但他还是一个人在战斗。他打工的房东的邻居见他干得好,就来找他商量。小王不得不停下手头的工作,为潜在客户解答疑惑或商讨解决方案。最终靠实力把潜在客户变成真正的客户。小王的名声就这样传开了。附近社区的知名人士找他商量装修方案或确定工期。小王每次都不得不停下手头的工作,专心为客户答疑解惑。客户离开后,他又开始工作。随着来找他的人越来越多,小王渐渐发现自己真正工作的时间越来越少,因为他把太多的时间花在了接待客户上。但是没办法,为了能够接到更多的工作,他必须要给客户提供这个咨询,而且必须花费这些时间。结果,工作时间被压缩了,工作也做不完了。我应该怎么办?其实解决的办法很简单,大家都能想到,那就是小王请了一个工人代劳。工人们完成工作后,先通过小王的测试,小王认为可以的时候再交给业主。小王继续为客户提供咨询服务,空闲时间也跟着唯一的工人一起工作。看来问题已经解决,一切都恢复了平衡。由于小王的狗屎运,每天来的客人太多了,这个新建立的平衡又被打破了。小王要日以继夜地提供咨询,所以他干脆停止了工作。而且因为工作越来越多,我只好招了第二个,第三个,第四个。..我们可以看到很多事情都在逐渐发生变化。小王逐渐从一个只能干活的工人,变成了一个只负责接待客户,不再工作的顾问。为了适应新的角色,小王不得不招了一个又一个工人为他工作,这样他才能完全从原来的工作岗位上解放出来。由此可见,随着事物的发展,分工是不可避免的,从而导致工作种类的增加。原来只有一个岗位,既负责工作又负责咨询。现在有两个职位,一个是负责咨询监理的,其实就是工头,一个是负责施工施工的,其实就是工人。这种“工头+工人”的模式在现实生活中非常普遍。工长给工人分配工作,检查工人的工作,回答工人的问题,实际上是两个岗位之间的协作。因此,分工的出现和协作代表了一种更先进、更高效的生产方式,至少在理论上是这样。Web容器对异步的支持看完上一节,希望大家记住这八个字,“各司其职,相互配合”。OK,现在进入程序世界。SpringMvc的本质是对JavaWeb的封装,所以要想更容易理解SpringMvc的异步,首先要理解JavaWeb的异步。JavaWeb的本质是一套标准(接口),而Web容器实现了这套标准,所以我们可以从Web容器的角度来理解JavaWeb的异步。无论使用什么框架来开发Javaweb应用程序,最终都会运行在web容器中,比如tomcat就是最常用的web容器。在启动SpringBoot的时候,可以看一下log中打印的线程名,其实就是tomcat线程池中的线程。可以多次请求,发现每次请求的线程ID都不一样。我们知道,其实在每次请求到来之后,Web容器都会从自己的线程池中取出一个线程运行JavaWeb应用来处理请求。当请求处理完后,线程会返回到线程池中去处理下一个请求。如果请求可以在很短的时间内得到处理,那是没有问题的。我们想象一下,如果请求执行的很慢,那么这个线程就无法返回,那么线程池中可用的线程数就会少一个。由于线程池的容量是有限的,如果同时来了很多执行很慢的请求,线程池中的线程就会被用完,短时间内回不来。此时不会处理其他请求。我们发现快速执行的请求和非常耗时的请求属于两种不同的东西,现在都是web容器的线程池中的线程从头到尾处理,就像一开始的小王一样。既要接待客户做咨询工作,又要等客户走后自己干活。这显然是低效的,唯一的办法就是将这两种工作分开,分配到两个岗位上。所以我们可以看到,小王招了很多工人,他专业的做咨询工作,交给工人。递送。我们可以把这个思想应用到web容器中,即web容器的线程池中的线程只用来处理执行速度快的请求,对应的就是小王只负责咨询和接收工作。对于非常耗时的请求,Web容器线程池中的线程会将请求交给其他专用线程池中的线程进行处理,对应小王将接收到的工作交给他的worker。Web容器线程池中的线程会去接受其他的请求,因为耗时的请求已经交接完毕。这对应小王要去接其他工作,因为之前的工作已经交给工人了。处理完请求后,专用线程池中的线程会返回给web容器线程池中的线程。这对应于工人完成工作后将工作交给小王验收。web容器线程池中的线程获取处理结果并将结果写入response中,对请求进行处理。这相当于小王将工人完成的工作交给了业主,才算施工完成。下面我们来分析一下,小王因角色转换带来的工作变化。一开始,小王一个人打工,小王有过三种工作。小王从业主手中接过活,小王自己干活,小王给业主送货。最后,小王当上了工头。这时,有四种工作。小王从业主手中接过工作,小王把工作交给工人,工人把完成的工作交给小王。王某交付给店主。经比对发现,小王为防止自己上班而介绍工人,由此产生的他与工人之间的协调互动。我们也来分析一下前后Web容器线程池线程的变化。一开始,线程处理所有的请求,可以分为三个阶段,线程接受请求,线程处理请求,线程写回响应。最后,线程的工作分为四个阶段。线程接受请求,线程将待处理的请求传递给特殊的线程池,特殊线程池将处理后的请求返回给线程,线程写回响应。经过对比发现,为了不让web容器线程池的线程处理耗时请求,引入了一个特殊的线程池,由此产生的它与特殊线程池的协调和交互。有没有发现线程池和小王的行为是完全对应的。而且他们都面临着同一个问题,就是把需要处理的任务交给别人,别人再把处理好的任务还给他。好吧,我现在告诉你,这就是JavaWeb异步处理的整体逻辑思路。化繁为简之后,其实就是两个动作,一去一来。执行过程自己交给1AsyncContextstartAsync()其他人返回执行过程1voiddispatch()以上两个方法完成一回一回两个动作,仅此而已。看到这里,有些人可能要失望了。传说中的“牛X和高大上”的异步处理,最后只有十四个字,“交出执行过程,返回执行过程”。可能有人会觉得异步处理应该跟客户端没有关系吧?其实不然,它纯粹是服务器端的把戏。并且单个请求的处理时间不会减少。就像你去饭店吃饭,你不知道你点的菜是一个厨师做的,还是后厨的多个厨师做的,一般不会在意。SpringMvc对异步处理的支持上面描述的异步处理逻辑只是一个规范(接口),没有实现。凡是想支持JavaWeb异步处理的,都需要在遵守本规范的前提下,提供一套实现。说白了就是要采用递交还回的模式,但是怎么交还怎么交还得自己实现,这个专门的线程池也得自己提供。SpringMvc提供了异步支持,所以它符合这个规范,它也定义了一个类似的接口来与JavaWeb规范进行交互。这个接口是AsyncWebRequest,它的实现类是StandardServletAsyncWebRequest。两种方法一样。交接1voidstartAsync()和返回1voiddispatch()在这两个方法的实现中,分别调用了JavaWeb规范中对应的方法,是与JavaWeb规范的交互。同时,SpringMvc本身有一个线程池,所以交出执行进程的操作在第一种方法中实现,归还执行进程的操作在第二种方法中实现。另一个问题是并不是所有的方法都需要异步处理,所以需要有一种方法告诉SpringMvc哪个方法需要异步处理。SpringMvc选择使用方法返回值的类型来区分。如果@RequestMapping方法的返回值类型是下面的,说明开发者要进行异步处理,所以SpringMvc进行异步处理。1Callable
