示例代码:许木木/Stream,文章和代码更配哦
同步阻塞式--BIO
一个客户端(连接)对应一个线程,只有一个服务线程为每个连接分配处理线程
缺点:缺乏弹性伸缩能力,服务端与客户端并发访问数呈1:1的正比关系,并发访问量过大,系统会产生线程堆栈溢出,创建新线程失败的问题,导致宕机或者僵死,不能对外提供服务。
核心代码实例:
TimeServer
TimeServerHandler:
TimeClient:
执行结果
伪异步IO
利用线程池和任务队列实现,将客户端的socket封装成一个task,即是通过线程池分配给每个连接当前为工作的线程。但是还是只有一个服务线程为连接分配线程池中的线程。
弊端:服务端处理读操作缓慢时会导致多个输入流阻塞,阻塞队列积满后后入列操作无法进行,最终导致大量连接超时。
核心代码:
server
程序执行结果:
非阻塞--NIO
1.缓冲区:有字节缓冲区、字符缓冲区、整型缓冲区等,通常是一个字节数组,提供了对数据的结构化访问以及维护读写位置等信息。
2.通道:channel是一个通道,网络数据通过channel读取和写入。通道与流的不同在于通道是双向的,流只是一个方向上移动。通道可以用于读、写或者同时读写。
channel分为两大类,用于网络读写的selectableChannel和用于文件操作的FileChannel。
3.多路复用器:提供了选择已经就绪的任务的能力,通过不断轮询注册在其上的channel,获取就绪状态的channel。一个多路复用器可以轮询多个channel,没有最大连接句柄的限制。
优点:客户端发起的连接操作是异步的,不需要被同步阻塞;socketchannel的读写操作也是异步的,不需要等待这个链路可用。连接数量不受限制。
示例执行结果
异步非阻塞--AIO
NIO2.0引入新的概念,提供了异步文件通道,和异步套接字通道的实现。提供了两种方式获取操作结果。
1. 通过Future类表示异步操作的结果
2. 在执行异步操作的时候传入一个channels。
CompletionHandler接口的实现类作为操作完成的回调。NIO2.0对应于事件驱动IO,不需要多路复用器进行轮询操作即可实现异步读写。
执行结果:
总结:
同步阻塞IO | 伪异步IO | 非阻塞IO | 异步IO | |
客户端:服务端 | 1:1 | M:N(M>N) | M:1(一个IO线程处理多个了客户端连接) | M:0(不需要启动额外的IO线程,被动回调) |
IO类型 | 同步阻塞 | 同步阻塞 | 同步非阻塞 | 异步非阻塞 |
API使用难度 | 简单 | 简单 | 非常复杂 | 复杂 |
调试难度 | 简单 | 简单 | 复杂 | 复杂 |
可靠性 | 相当差 | 差 | 高 | 高 |
吞吐量 | 向当低 | 中 | 高 | 高 |