1 前言
对于网络中的IO模型,大多数人可能只是简单的了解下,而没有对于其进行深入的了解。该文章大致的讲解了java开发过程中
遇到的Io模型。
2 BIO
2.1 介绍
阻塞性IO,这种模型会通过一个独立的线程进行监听,当客户端请求一个连接后,服务端会产生一个线程对请求进行处理,处理完成后,返回响应给客户端,最后进行销毁。同时,这种模型在线程进行处理请求时会阻塞当前线程,必须等待服务端处理完毕,关闭连接。
2.2 优点
- 处理起来相对比较简单,只需要创建线程处理请求即可。
2.3 缺点
- 当并发量增大之后,服务器需要对多个请求进行相应的线程处理,
2.4 例子
- Socket套接字,服务端需要创建SocketServer对端口进行监听,处理请求。
- java传统IO流。
- Tomcat的BIO阻塞模式。
延伸:
我们经常会在面试中被问到Spring是否是单例的,为什么默认是单例。因为之前大多Tomcat的模型大多是阻塞模型,在并发的情况下可能会导致线程
不安全的情况。当使用NIO模型时,这种情况也就不会发生了。
3 NIO
3.1 介绍
- 传统的阻塞IO使用的是流,例如字节流,字符流,在这种情况下,线程必须阻塞到流处理完毕。而NIO处理的是缓冲区.
其实缓冲区只是个对象数组而已。在NIO中,所有的数据都是从缓冲区读的,所有数据也是写到缓冲区的。 - NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。
3.2 缓冲区问题
这边可能会有人问到?这个和传统IO的缓冲流BufferReader有什么区别。
1. 传统IO为什么要用缓冲区?
假设我们用字符流进行读取,只能一个一个字符进行读取。而如果使用了缓冲流,我们可以一行一行进行读取。
2. 那字符流向缓冲流进行转换的过程难道不是一个一个字符写入到缓冲流的对象数组中的吗?
看源码:
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);关注这句话
count += len;
return this;
}
3 NIO由于缓冲区的存在可以做到非阻塞。
3.3 原理
NIO采用了多路复用器Selector,Selector会不断轮询注册在其上的channel。如果channel上发生了读或者写事件,这个channel就是就绪状态,
会被selector轮询出来,随后对这个channel进行处理。同时由于使用了epoll模型,只需要一个线程进行selector的轮询,做到了IO多路复用。
3.4 优点
- 增强了服务器处理高并发的能力,减少了系统负载。
3.5 缺点
- 调试难度复杂
- 实现比较麻烦。这方面不懂,嘻嘻~~
3.6 例子
- Tomcat的NIO模型。
- redis的单线程模型。