NIO的工作流程

  • Post author:
  • Post category:其他



一、传统IO(BIO)和NIO

BIO是同步阻塞的,即一个请求分配一个线程,就是再客户端发送请求到服务器的时候,服务器会为这个客户端分配一个线程去处理相关的读写操作,且在此期间,该线程是阻塞的,不能接收其他客户端的请求。这样的阻塞如果是单线程的话,在多用户的情况下会造成非常不好的系统体验,且会造成cpu的浪费,所以需要用多线程来处理这样的请求。但是使用多线程也有缺点:线程创建和销毁的成本较高;线程还会占有一定的内存,如果线程的数量较多,数千的时候,会造成吃掉一半的jvm内存;另外线程切换的成本也很高,因为线程切换需要保存线程的上下文信息,方便下次线程被唤醒后继续处理。

NIO是面对缓冲区的,是同步非阻塞的,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。


二、NIO的三个核心组件介绍

1、selector

selector是NIO的选择器,NIO的同步功能就是靠selector来实现的,多个channel可以注册到同一个selector上,然后用一个线程来管理一个selector选择器,就实现了通过一个线程来管理多个通道实现客户端同步请求的效果。

我们可以将Server端的监听连接请求的事件和处理请求的事件放在一个线程中,但是在事件应用中,我们通常会把它们放在两个线程中:一个线程专门负责监听客户端的连接请求(OP_ACCEPT),而且是


以阻塞方式执行的


;另外一个线程专门负责处理请求(OP_READ、OP_WRITE等),这个专门处理请求的线程才会真正采用NIO的方式

2、channel

NIO通道是一个

对象

,可以通过它

(从客户端写入缓冲区)

读取和写入数据

(从缓冲区通过通道发送给客户端)

,可以理解为是对原I/O包中流的模拟,通道和流的区别在于,通道是双向的,通道可用于

读、写或者同时读写

,而流只能是一个方向,inputstream是读,outputstream是写。

3、buffer

NIO缓冲区就是一个数组,有byteBuffer、charBuffer、floatBuffer、LongBuffer等。

数据总是从通道读取到缓冲区,或者从缓冲区写入到通道


三、先看下服务器端和客户端的代码

1、服务器端

public void selector() throws IOException {


//先给缓冲区申请内存空间

ByteBuffer buffer = ByteBuffer.allocate(1024);

//打开Selector为了它可以轮询每个 Channel 的状态

Selector selector = Selector.open();

ServerSocketChannel ssc = ServerSocketChannel.open();


ssc.configureBlocking(fal



版权声明:本文为flyingdog123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。