当学习Java的NIO和IO时,有个问题会跳入脑海当中:何时该用IO,何时用NIO?缓存
下面的章节中笔者会试着分享一些线索,包括二者之间的区别,使用场景以及他们是如何影响代码设计的。服务器
下面这个表格归纳了NIO和IO的主要差别。咱们会针对每一个差别进行解释。网络
IO | NIO |
---|---|
Stream oriented | Buffer oriented |
Blocking IO | No blocking IO |
Selectors |
第一个重大差别是IO是面向流的,而NIO是面向缓存区的。这句话是什么意思呢?socket
Java IO面向流意思是咱们每次从流当中读取一个或多个字节。怎么处理读取到的字节是咱们本身的事情。他们不会再任何地方缓存。再有就是咱们不能在流数据中向先后移动。若是须要向先后移动读取位置,那么咱们须要首先为它建立一个缓存区。学习
Java NIO是面向缓冲区的,这有些细微差别。数据是被读取到缓存当中以便后续加工。咱们能够在缓存中向向后移动。这个特性给咱们处理数据提供了更大的弹性空间。固然咱们任然须要在使用数据前检查缓存中是否包含咱们须要的全部数据。另外须要确保在往缓存中写入数据时避免覆盖了已经写入可是还未被处理的数据。spa
Java IO的各类流都是阻塞的。这意味着一个线程一旦调用了read(),write()方法,那么该线程就被阻塞住了,知道读取到数据或者数据完整写入了。在此期间线程不能作其余任何事情。线程
Java NIO的非阻塞模式使得线程能够经过channel来读数据,而且是返回当前已有的数据,或者什么都不返回若是但钱没有数据可读的话。这样一来线程不会被阻塞住,它能够继续向下执行。设计
一般线程在调用非阻塞操做后,会通知处理其余channel上的IO操做。所以一个线程能够管理多个channel的输入输出。code
Java NIO的selector容许一个单一线程监听多个channel输入。咱们能够注册多个channel到selector上,而后而后用一个线程来挑出一个处于可读或者可写状态的channel。selector机制使得单线程管理过个channel变得容易。server
开发中选择NIO或者IO会在多方面影响程序设计:
显而易见使用NIO的API接口和使用IO时是不一样的。不一样于直接冲InputStream读取字节,咱们的数据须要先写入到buffer中,而后再从buffer中处理它们。
数据的处理方式也随着是NIO或IO而异。 在IO设计中,咱们从InputStream或者Reader中读取字节。假设咱们如今须要处理一个按行排列的文本数据,以下:
Name: Anna Age: 25 Email: anna@mailserver.com Phone: 1234567890
这个处理文本行的过程大概是这样的:
InputStream input = ... ; // get the InputStream from the client socket BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String nameLine = reader.readLine(); String ageLine = reader.readLine(); String emailLine = reader.readLine(); String phoneLine = reader.readLine();
NIO容许咱们只用一条线程来管理多个通道(网络链接或文件),随之而来的代价是解析数据相对于阻塞流来讲可能会变得更加的复杂。
若是你须要同时管理成千上万的连接,这些连接只发送少许数据,例如聊天服务器,用NIO来实现这个服务器是有优点的。相似的,若是你须要维持大量的连接,例如P2P网络,用单线程来管理这些 连接也是有优点的。这种单线程多链接的设计能够用下图描述:
Java NIO: A single thread managing multiple connections
若是连接数不是不少,可是每一个连接的占用较大带宽,每次都要发送大量数据,那么使用传统的IO设计服务器多是最好的选择。下面是经典IO服务设计图:
Java IO: A classic IO server design - one connection handled by one thread.