Java 网络IO编程(BIO、NIO、AIO)

Java 网络IO编程(BIO、NIO、AIO)

 

本概念

BIO编程

传统的BIO编程

代码示例:html

  View Code

该模型最大的问题就是缺少弹性伸缩能力,当客户端并发访问量增长后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,Java中的线程也是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧降低,随着访问量的继续增大,系统最终就死-掉-了。编程

伪异步I/O编程

代码示例:数组

  View Code

该模式使用线程池,咱们就有效的控制了线程的最大数量,保证了系统有限的资源的控制,实现了N:M的伪异步I/O模型。可是,正由于限制了线程数量,若是发生大量并发请求,超过最大数量的线程就只能等待,直到线程池中的有空闲的线程能够被复用。而对Socket的输入流就行读取时,会一直阻塞,直到发生:缓存

  •     有数据可读
  •     可用数据以及读取完毕
  •     发生空指针或I/O异常

    因此在读取数据较慢时(好比数据量大、网络传输慢等),大量并发的状况下,其余接入的消息,只能一直等待,这就是最大的弊端。服务器

NIO 编程

简介

 

NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不一样的套接字通道实现。网络

新增的着两种通道都支持阻塞和非阻塞两种模式。数据结构

阻塞模式使用就像传统中的支持同样,比较简单,可是性能和可靠性都很差;非阻塞模式正好与之相反。并发

对于低负载、低并发的应用程序,可使用同步阻塞I/O来提高开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用NIO的非阻塞模式来开发。框架

缓冲区 Buffer

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

    在NIO库中,全部数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是写入到缓冲区中。任什么时候候访问NIO中的数据,都是经过缓冲区进行操做。

    缓冲区其实是一个数组,并提供了对数据结构化访问以及维护读写位置等信息。

    具体的缓存区有这些:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他们实现了相同的接口:Buffer。

具体介绍可参照 http://ifeve.com/buffers/

通道 Channel

   咱们对数据的读取和写入要经过Channel,它就像水管同样,是一个通道。通道不一样于流的地方就是通道是双向的,能够用于读、写和同时读写操做。

    底层的操做系统的通道通常都是全双工的,因此全双工的Channel比流能更好的映射底层操做系统的API。

    Channel主要分两大类:

  •     SelectableChannel:用户网络读写
  •     FileChannel:用于文件操做

    后面代码会涉及的ServerSocketChannel和SocketChannel都是SelectableChannel的子类。

多路复用器 Selector

 Selector是Java  NIO 编程的基础。

    Selector提供选择已经就绪的任务的能力:Selector会不断轮询注册在其上的Channel,若是某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,而后经过SelectionKey能够获取就绪Channel的集合,进行后续的I/O操做。

    一个Selector能够同时轮询多个Channel,由于JDK使用了epoll()代替传统的select实现,因此没有最大链接句柄1024/2048的限制。因此,只须要一个线程负责Selector的轮询,就能够接入成千上万的客户端。

 

代码示例:

  View Code

AIO编程

代码示例:

  View Code

各类I/O的对比

    先以一张表来直观的对比一下:

    03

    具体选择什么样的模型或者NIO框架,彻底基于业务的实际应用场景和性能需求,若是客户端不多,服务器负荷不重,就没有必要选择开发起来相对不那么简单的NIO作服务端;相反,就应考虑使用NIO或者相关的框架(Netty,Nima)了。