1.相关概念
1.1 同步 和 异步
- 同步 :一个任务完成之前不能做其它操作,必须等待完成(打电话)
- 异步: 一个任务完成之前,无需等待,就可以进行其它操作(发短信,不要等待对方回复就可以做其它事情)
1.3 阻塞 和 非阻塞 IO
java IO的各种流都是阻塞的。这意味着,当一个线程调用流的读或写时,
该线程会被阻塞,直到有一些数据被读取完,或者数据被完全写入。
该线程在此期间不能再干其他任何事情了。
Java NIO 的非阻塞模式,
使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,
如果目前没有什么数据可用时,就什么都不会获取, 而不是保持线程阻塞,
所以直到数据变得可以读取之前 ,该线程可以继续做其他的事情。
非阻塞写也是如此。一个线程请求写入一些数据到某通道,
但不需要等待它完全写入, 这个线程同时可以去做别的事情。
线程通常将非阻塞IO的空闲事件用在其他通道上执行IO操作,
所以单独一个线程可以管理多个输入和输出通道.
2. BIO NIO AIO
2.1 概念
- BIO:同步阻塞IO,服务器实现模式为一个连接一个线程。
即一个客户端请求,服务器就需要开启一个线程进行处理, 没处理完成之前此线程不能做其它操作。 - NIO:同步非阻塞,服务器实现模式为一个IO请求一个线程,
即客户端发送的连接请求都会注册到多路复用器上, 多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。 - AIO(NIO 2.0): 异步非阻塞,服务器实现模式为一个有效请求一个线程,
发起和处理IO请求都是异步的(NIO 2.0 引入了新的异步通道的概 念,并提供了异步文件通道和异步套接字通道的实现)
2.2 适用场景
- BIO方式适用于连接数目比较小且固定的架构,对服务器资源要求比较高,
并发局限于应用中。 - NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,
并发局限于应用中,编程较复杂。 - AIO方式使用于连接数目多且连接比较长(重操作)的架构,
比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
3.NIO的三大核心
3.1 Channels
基本上,所有的IO在 NIO中 都是从一个Channel开始。Channel有点像流。
数据可以从Channel中读到Buffer中,也可以从Buffer读到Channel中。
Channel---> Buffer
Buffer ---> Channel
以下是Java NIO中的一些主要Channel的实现:
FileChannel
DataGramChannel
SocketChannel
ServerSocketChannel
正如你看到的,这些通道涵盖了UDP/TCP网络IO,以及文件IO。
3.2 Buffers
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。
这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
以下是JAVA NIO里关键的Buffer实现:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
3.3 Selector
Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。
Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
Selector允许单线程处理多个Channel。如果你的应用打开了多个连接(通道),但每个连接的流量
都很低,使用Selector九会很方便。
这是一个单线程中使用一个Selector处理3个Channel的图示
Thread
|
Selector
———————————————————
| | |
channel channel channel
要使用Selector,得向Selector注册Channel,然后调用它得select方法
这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理
这些事件,事件的例子有如 新连接进来,数据接收等。
为什么使用Selector?
仅用单个线程处理多个Channel的好处是,只需要更少的线程来处理通道。
事实上可以只用一个线程处理所有的通道。
对于操作系统来说,线程之间上下文切换的开销很达,
而且每个线程都会占用系统一些资源,因此使用的线程越少越好。
4. IO和NIO的区别
4.1 面向流与面向缓冲
JAVA NIO 和 IO之间第一个最大的区别是,IO是面试流的,NIO是面向缓冲区的.
Java IO面向流意味着每次从流中读一个或多个字节,直至读取完所有字节,
它们没有被缓存在任何地方.Java NIO 数据读取到一个它稍后处理的缓冲区,
需要时可在缓冲区前后移动.这就增加了处理过程中的灵活性.
4.2 阻塞与非阻塞IO
java IO的各种流都是阻塞的。这意味着,当一个线程调用流的读或写时,
该线程会被阻塞,直到有一些数据被读取完,或者数据被完全写入。
该线程在此期间不能再干其他任何事情了。
Java NIO 的非阻塞模式,使一个线程从某通道发送请求读取数据,
但是它仅能得到目前可用的数据, 如果目前没有什么数据可用时,就什么都不会获取,
而不是保持线程阻塞,所以直到数据变得可以读取之前,该线程可以继续做其他的事情。
非阻塞写也是如此。一个线程请求写入一些数据到某通道,但补需要等待它完全写入,
这个线程同时可以去做别的事情。线程通常将非阻塞IO的空闲事件用在其他通道上执行IO操作,
所以单独一个线程可以管理多个输入和输出通道.
4.3 选择器
Java NIO的选择器允许一个单独的线程来监视多个输入通道,
你可以注册多个通道共同使用一个选择器,
然后使用一个单独的线程来选择通道: 这些通道里面已经有可以处理的输入,
或者选择已准备写入的通道.这种选择机制,使得一个单独的线程很容易来管理多个通道.
|