Java NIO详解

NIO含义

New I/O,原因在于相对于之前的I/O类库是新增的。

由于之前老的I/O类库是阻塞I/O,New I/O类库的目标就是要让Java支持非阻塞I/O,非阻塞I/O(Non-block I/O)更合适。

SocketChannel和ServerSocketChannel

与Socket类和ServerSocket类相对应,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。

低负载、低并发的应用程序可以选择同步阻塞I/O以降低编程复杂度;对于高负载、高并发的网络应用,需要使用NIO的非阻塞模式进行开发。

NIO类库简介

NIO弥补了原来同步阻塞I/O的不足,它在标准Java代码中提供了高速的、面向块的I/O。

通过定义包含数据的类,以及通过以块的形式处理这些数据,NIO不用使用本机代码就可以利用低级优化,这是原来的I/O包所无法做到的。

NIO类库简介 缓冲区Buffer

Buffer是一个对象,它包含一些要写入或者要读出的数据。

在NIO类库中加入Buffer对象,体现了新库与原I/O的一个重要区别。

在面向流的I/O中,可以将数据直接写入或者将数据直接读到Stream对象中。

在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。

缓冲区实质上是一个数组。

缓冲区不仅仅是一个数组,缓冲区提供了对数据的结构化访问以及维护读写位置(limit)等信息。

一个ByteBuffer提供了一组功能用于操作byte数组。

每一种Java基本类型(除了Boolean类型)都对应有一种缓冲区:

ByteBuffer:字节缓冲区

CharBuffer:字符缓冲区

ShortBuffer:短整型缓冲区

IntBuffer:整形缓冲区

LongBuffer:长整形缓冲区

FloatBuffer:浮点型缓冲区

DoubleBuffer:双精度浮点型缓冲区

Java NIO详解

每一个Buffer类都是Buffer接口的一个子实例。除了ByteBuffer,每一个Buffer类都有完全一样的操作,只是它们所处理的数据类型不一样。

因为大多数标准I/O操作都使用ByteBuffer,所以它在具有一般缓冲区的操作之外还提供了一些特有的操作,以方便网络读写。

NIO类库简介 通道Channel

Channel是一个通道,网络数据通过Channel读取和写入。

通道与流的不同之处在于通道是双向的,流只是在一个方向上移动(一个流必须是InputStream或者OutputStream的子类),而通道可以用于读、写或者二者同时进行。

因为Channel是全双工的,所以它可以比流更好地映射底层操作系统的API。特别是在UNIX网络编程模型中,底层操作系统的通道都是全双工的,同时支持读写操作。

Java NIO详解

自顶向下看,前三层主要是Channel接口,用于定义它的功能,后面是一些具体的功能类(抽象类)。从类图可以看出,实际上Channel可以分为两大类:用于网络读写的SelectableChannel和用于文件操作的FileChannel。

ServerSocketChannel和SocketChannel都是SelectableChannel的子类

多路复用器Selector

多路复用器Selector是Java NIO编程的基础

多路复用器提供选择已就绪的任务的能力。

Selector会不断地轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channnel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。

一个多路复用器Selector可以同时轮询多个Channel,由于JDK使用了epoll()代替传统的select实现,所以它并没有最大连接句柄1024/2048的限制。这也就意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端,这确实是个非常巨大的进步。

Java NIO详解

下面用代码简单描述这个过程:

Java NIO详解

使用NIO技术编写TimeServer

Java NIO详解

Java NIO详解

使用NIO技术编写TimeClient原理讲解

时序图:

Java NIO详解

用代码讲解一下过程:

Java NIO详解

使用NIO技术编写TimeClient

Java NIO详解

Java NIO详解

注意

下面这种关闭socket的方法是错误的

Java NIO详解

如果服务端没有对这种情况进行处理会出现一下的错误:

Java NIO详解

服务端最好是在读取数据的时候做一下处理:

Java NIO详解

优势

NIO编程的难度比同步阻塞BIO大很多。

请注意以上的代码中并没有考虑“半包读”和“半包写”,如果加上这些,代码将会更加复杂。。

(1)客户端发起的连接操作是异步的,可以通过在多路复用器注册OP_CONNECT等待后续结果,不需要像之前的客户端那样被同步阻塞。

(2)SocketChannel的读写操作都是异步的,如果没有可读写的数据它不会同步等待,直接返回,这样I/O通信线程就可以处理其他的链路,不需要同步等待这个链路可用。

(3)线程模型的优化:由于JDK的Selector在Linux等主流操作系统上通过epoll实现,它没有连接句柄数的限制(只受限于操作系统的最大句柄数或者对单个进程的句柄限制),这意味着一个Selector线程可以同时处理成千上万个客户端连接,而且性能不会随着客户端的增加而线性下降。因此,它非常适合做高性能、高负载的网络服务器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值