JDK1.4推出NIO1.0
同步阻塞模式(BIO):一请求一应答的通信模型,弊端:面对访问量的激增,只能硬件扩容
BIO的服务端通信模型
1.通常由一个独立的Acceptor线程负责监听客户端的连接
2.接收到客户端连接请求之后,为客户端连接创建一个新的线程处理请求的消息
3.处理请求后,返回应答消息给客户端,线程销毁
一个线程处理一个Socket连接,因为Java Socket是通过InputStream和OutputStream来进行网络读写操作,而这俩个的读写都是阻塞模式,所以当某个Socket链路的读写操作没有完成时,排在后面的Socket连接是无法得到处理的,长时间的等待可能会导致超时,因此在同步阻塞模式下,通常会采用一个Socket链路独占一个线程的模型。
对BIO的优化:
采用线程池和任务队列实现一种叫做伪异步的IO通信框架
服务端接收到客户端的连接时,不创建独立的线程,而是将Socket连接封装成Task,将Task放入线程池的任务队列中执行,这样就可以有效控制线程的规模,防止线程膨胀导致的系统崩溃,利用线程池,可以重用线程,相比于BIO,性能有很大提高。
弊端:无法从根本上解决问题,由于IO读写会被阻塞,当并发量激增或者网络时延增大之后,线程的执行时间会被拉长,它导致缓存在任务队列中的任务不断堆积,最终导致内存溢出或者拒绝新任务的执行。
JDK1.4之后推出非阻塞IO(NIO)
NIO API主要由三部分组成:缓冲区(Buffers)、通道(Channels)和Selector组成
NIO 是基于事件驱动思想实现的,它采用Reactor模式实现,主要用来解决BIO模型中一个服务端无法同时并发处理大量客户端连接的问题。
NIO 基于Selector进行轮询,当socket有数据可读、可写、连接完成、新的TCP请求接入事件时,操作系统内核会触发Selector返回准备就绪的SelectionKey的集合,通过SelectableChannel进行读写操作。
SelectableChannel的读写操作都是异步非阻塞的,当由于数据没有就绪导致读半包时,立即返回,不会同步阻塞等待数据就绪,当TCP缓冲区数据就绪之后,会触发Selector的读事件,驱动下一次读操作。