我类比一下BIO\NIO\AIO,服务器就是餐馆,客户端就是来餐馆的顾客。
BIO: 进来一个顾客(连接),餐馆(服务器)就分配一个服务员(线程)来服务它,这时候顾客很墨迹想半天都不知道点啥(请求的IO还没有到),这个服务员(线程)就一直等呀等。
一个顾客进来就给它分配一个服务员;一个连接进来就给它分配一个线程。
问题:顾客多了,餐馆没有那么多服务员,餐馆就瘫痪了。JVM的线程超过最大数量了,服务器爆了。
NIO: 既然顾客(连接)很墨迹(IO流数据没到),那就一个服务员(线程)在巡堂(多路复用),挨个轮询看哪个桌子的顾客想好了。如果一个顾客可以点餐了(IO流有数据了),就给它喊一个服务员过来(创建一个线程)。
所有的顾客进来都只有一个服务员巡堂;所有的连接进来都对应一个线程,一个请求对应一个线程。
当顾客想好了可以点餐了,分配一个专属服务员;当一个线程的IO流到达,分配一个线程。
问题:给一个点餐请求分配了服务员,但是服务员发现点的菜还没有买回来,服务员只有等着菜买回来才能给厨师。服务器的线程看到请求过来了,但是处理请求所需要的资源还暂时得不到,线程只有继续等着。
AIO: 既然要等到菜(可用资源)有了,服务员(线程)才能去给厨师下单(处理请求),于是餐馆让顾客在APP上下单,下单成功都有菜(OS先接收IO流的数据成功),这时候APP(OS)通知服务员(线程)才来把菜单交给厨师(处理请求)。
有些因为菜没有而无效的点餐,就不会分配服务员来服务了,不会为了无效的点餐分配服务员;不会为了无效的请求分配线程,* 一个有效的请求一个线程 **
BIO
服务器上的监听发现有一个客户端的连接过来了,就创建一个服务器端的线程与服务器连接。此时可能客户端的请求还没有来,线程就一直阻塞,等客户端的输入流有数据。
这样每个连接都会对应一个服务器的连接,而IO流是很慢很慢的,非常费服务器的资源。
NIO
为了解决BIO一个请求一个服务器端线程,而大量线程都在等着IO流的弊端。NIO让所有的客户端连接都对应一个服务器端的线程。
AIO
为了解决NIO启动服务器线程处理输入流的时候,后端资源还没有到位,线程仍然阻塞等待资源的问题,让客户端的输入流先让OS接收,OS接收后通知应用启动线程处理请求,实现了异步非阻塞。
BIO是同步阻塞方式:所谓阻塞就是等着线程啥都不干光等着IO流的数据到达,必须等到IO流到达写入到程序空间才能做其他事情。
NIO是同步非阻塞:线程不会一直等着IO流的到达而不能做别的事,而是不断的轮询是否有数据到达。IO流到达java就会有一个线程立马来处理,这是个同步的过程。
AIO是异步非阻塞方式:客户端的IO过来,被操作系统先接收了才通知用户程序,这样没有应用的线程阻塞等着IO流;然后用户的线程也不直接接收IO流的数据,而是由操作系统收下后通知它处理,因此它是异步的。