1 问题背景
毕设做的是通过缓存、负载均衡提高并发加载数据的速度。随后又了解到解决并发的核心基础其实有Linux IO模型。逐步深入后还是没有真正了解Linux IO模型。随后又研究了Socket通信,最后来研究Netty以Java的角度了解Linux IO模型。
学习资源参考自b站的尚硅谷的Netty教程视频
2 前言
本文需要有一定的网络通信、网络编程的知识,如果是0基础推荐看看我写的解决高并发的核心——LinuxIO模型、高并发基础之Socket入门,为研究Netty打下基础。
3 BIO
3.1 简介
BIO即阻塞IO
3.2 工作机制
如上图所示,BIO工作机制是客户端来多少个连接,服务端就创建多少个线程来处理,并且这些线程是阻塞等待的。即使客户端没有发送数据给服务端,服务端仍会阻塞等待客户端发送数据,在这期间会浪费系统资源。BIO的优点是实现简单,缺点是浪费系统资源。
学习过程的相关源码参考:gmall-learning-netty模块的bio包
4 NIO
4.1 简介
Java NIO,全称是Java Non-blocking IO,是jdk1.4开始提供的一套新的输入/输出的新特性,被统称NIO,也可以叫做New IO,是同步非阻塞的意思。NIO相关的类放在java.nio包下,并且对原java.io包中的很多类进行改写。
4.2 三大核心组件
NIO三大核心组件分别是Channel(通道)、Selector(选择器)、Buffer(缓冲区)
4.3 工作机制
概要:如上图所示,NIO改正了BIO的缺点,如上图中的蓝色区域部分,服务端只需用一个线程就可以管理客户端发来的连接请求以及处理通信过程中的数据读写。服务端大大节省了资源开销,仅通过一个线程就可以处理若干个请求。当然服务端还可以开启若干个这种线程,如上图所示,图中有3个类似于蓝色部分的模型。
主要工作机制:首先不需要过于纠结图中客户端到Selector的数据流向,暂且了解以下的工作机制。 服务端创建一个ServerSocketChannel,然后往Selector上注册,客户端也创建SocketChannel并且注册到Selector上。服务端创建的一个线程对应一个Selector,一个Selector对应若干个Channel,每个Channel都对应一个Buffer以及一个客户端。上图中的其中一个Selector有3个客户端,3个Channel。Selector会根据不同的事件切换到对应的Channel上。数据的读写都是从Channel(通道)读取到Buffer(缓冲区)中或者从Buffer(缓冲区)写入到Channel(通道)中 。因此NIO的Buffer是双向的。而BIO的数据流是单向的,只能单向地读、单向地写。Buffer的读写需要使用flip()
方法切换。
5 NIO与BIO的比较(重要)
- BIO以流的方式处理数据,NIO以块的方式处理数据,流I/O的效率比块I/O高很多
- BIO是阻塞的,NIO则是非阻塞的
- BIO是基于字节流和字符流进行操作的,而NIO是基于Channel(通道)和Buffer(缓冲区)进行操作的,数据总是从通道读取到缓冲区,或者从缓冲区写入到通道中。Selector(选择器)用于监听多个通道的事件(比如:客户端连接请求,数据到达等)。因此使用单个线程可以监听多个客户端通道。