描述IO,咱们须要从两个层面:html
BIO | NIO | AIO 以Java的角度,理解,linux c里也有AIO的概念(库),本文只从Java角度入手。java
在JDK1.4以前,用Java编写网络请求,都是创建一个ServerSocket,而后,客户端创建Socket时就会询问是否有线程能够处理,若是没有,要么等待,要么被拒绝。即:一个链接,要求Server对应一个处理线程。linux
在Java里的由来,在JDK1.4及之后版本中提供了一套API来专门操做非阻塞I/O,咱们能够在java.nio包及其子包中找到相关的类和接口。因为这套API是JDK新提供的I/O API,所以,也叫New I/O,这就是包名nio的由来。这套API由三个主要的部分组成:缓冲区(Buffers)、通道(Channels)和非阻塞I/O的核心类组成。在理解NIO的时候,须要区分,说的是New I/O仍是非阻塞IO,New I/O是Java的包,NIO是非阻塞IO概念。这里讲的是后面一种。编程
NIO自己是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题: 在使用同步I/O的网络应用中,若是要同时处理多个客户端请求,或是在客户端要同时和多个服务器进行通信,就必须使用多线程来处理。也就是说,将每个客户端请求分配给一个线程来单独处理。这样作虽然能够达到咱们的要求,但同时又会带来另一个问题。因为每建立一个线程,就要为这个线程分配必定的内存空间(也叫工做存储器),并且操做系统自己也对线程的总数有必定的限制。若是客户端的请求过多,服务端程序可能会由于不堪重负而拒绝客户端的请求,甚至服务器可能会所以而瘫痪。windows
NIO基于Reactor,当socket有流可读或可写入socket时,操做系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操做系统。
也就是说,这个时候,已经不是一个链接就要对应一个处理线程了,而是有效的请求,对应一个线程,当链接没有数据时,是没有工做线程来处理的。服务器
与NIO不一样,当进行读写操做时,只须直接调用API的read或write方法便可。这两种方法均为异步的,对于读操做而言,当有流可读取时,操做系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操做而言,当操做系统将write方法传递的流写入完毕时,操做系统主动通知应用程序。
便可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。
在JDK1.7中,这部份内容被称做NIO.2,主要在java.nio.channels包下增长了下面四个异步通道:网络
其中的read/write方法,会返回一个带回调函数的对象,当执行完读取/写入操做后,直接调用回调函数。多线程
说道实现原理,还要从操做系统的IO模型上了解并发
按照《Unix网络编程》的划分,IO模型能够分为:阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO,按照POSIX标准来划分只分为两类:同步IO和异步IO。如何区分呢?首先一个IO操做其实分红了两个步骤:发起IO请求和实际的IO操做,同步IO和异步IO的区别就在于第二个步骤是否阻塞,若是实际的IO读写阻塞请求进程,那么就是同步IO,所以阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO,若是不阻塞,而是操做系统帮你作完IO操做再将结果返回给你,那么就是异步IO。阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,若是阻塞直到完成那么就是传统的阻塞IO,若是不阻塞,那么就是非阻塞IO。app
收到操做系统的IO模型,又不得不提select/poll/epoll/iocp,关于这四个的理解,很少作解释,本身还没理解到位。
能够理解的说明是:在Linux 2.6之后,java NIO的实现,是经过epoll来实现的,这点能够经过jdk的源代码发现。而AIO,在windows上是经过IOCP实现的,在linux上仍是经过epoll来实现的。
这里强调一点:AIO,这是I/O处理模式,而epoll等都是实现AIO的一种编程模型;换句话说,AIO是一种接口标准,各家操做系统能够实现也能够不实现。在不一样操做系统上在高并发状况下最好都采用操做系统推荐的方式。Linux上尚未真正实现网络方式的AIO。
说到底层,要说Linux系统编程,这里本身也不熟悉,有待后来人补充了。
只笼统的说一个:AIO实现
在windows上,AIO的实现是经过IOCP来完成的,看JDK的源代码,能够发现
WindowsAsynchronousSocketChannelImpl
看实现接口:
implements Iocp.OverlappedChannel
再看实现方法:里面的read0/write0方法是native方法,调用的jvm底层实现,虚拟机技术不熟悉,不献丑了。
在linux上,AIO的实现是经过epoll来完成的,看JDK源码,能够发现,实现源码是:
UnixAsynchronousSocketChannelImpl
看实现接口:
implements Port.PollableChannel
这是与windows最大的区别,poll的实现,在linux2.6后,默认使用epoll。
最后,几篇解释的不错的文章: