文章目录
为什么用Selector
这篇会比前面两篇长,因为要说IO模型的一些问题。
既然有了Channel和Buffer,我们就可以通信了,那这个Selector是做什么的?
首先,我们很容易发现,之前的使用都是在单线程下,单个客户端与服务端的通信。
如果我们服务器需要处理多个连接呢?
我们前面说过SocketChannel和ServerSocketChannel的阻塞和非阻塞模式。
下面会简单的说一下阻塞和非阻塞IO,重点在多路复用。不是说操作系统知识中的纯粹抽象的IO模型,而是IO模型在NIO中的体现。(之后会单独写一篇操作系统中的IO模型,相当于抽象版本)
使用阻塞模式:
意味着accept,read,write这些方法都要阻塞,我们单个线程基本处理不了多个连接。因为你调用这个Channel的阻塞方法,线程阻塞了,这时候别的Channel准备好了数据,你却在阻塞状态等待之前的Channel。
当然还有多线程,使用多线程也有一些问题。当连接数过多,我们要有很多线程处理不同的连接。且线程过多必然导致上下文切换频繁,性能下降。且太多线程可能发生OOM。
那么不用阻塞模式,使用非阻塞模式呢?
非阻塞模式下的accept,read,write的方法发现没有接入的连接或者读写缓冲区没准备好,不会阻塞线程等待,而是直接返回,一般我们循环轮询。
但非阻塞模式下,即使在没有连接建立或者没有可读数据或者写缓冲区没准备好的情况,线程仍然在不断运行,白白浪费了 cpu。
学过IO模型的都知道,上面就是两种IO模型,阻塞IO与非阻塞IO。
那么有没有更好的方案?
当然有就是前面文章提到几次的多路复用
下篇文章要说的Selector就是基于多路复用的思想。
简单来说就是一个Selector监听多个Channel,且为非阻塞模式,实现哪里有可读可写事件就可得知,然后处理。即阻塞等待读写事件发生,有事件再去处理。不需要像非阻塞一样一直空转cpu来查询有没有事件。充分利用线程。
一个线程就可以监控多个Channel。不需要多个线程来监控了。充分利用单个线程。
单说可能有点抽象。配合具体例子应该就能明白了。
下篇在具体写Selector到底是个什么,怎么使用,注意哪些东西。
结语
今天博客写的有点晚,再写睡不了觉了。所以先写了个引子,有点水哈哈。明天再更Selector。
感谢阅读,欢迎批评指正