本文将先容 Java NIO 中三大组件 Buffer、Channel、Selector 的利用。
原来要一起先容非阻塞 IO 和 JDK7 的异步 IO 的,不外因为之前的文章真的太长了,有点影响读者阅读,所以这里将它们放到另一篇文章中举办先容。
Buffer
一个 Buffer 本质上是内存中的一块,我们可以将数据写入这块内存,之后从这块内存获取数据。
java.nio 界说了以下几个 Buffer 的实现,这个图读者应该也在不少处所见过了吧。
其实焦点是最后的 ByteBuffer,前面的一大串类只是包装了一下它罢了,我们利用最多的凡是也是 ByteBuffer。
我们应该将 Buffer 领略为一个数组,IntBuffer、CharBuffer、DoubleBuffer 等别离对应 int[]、char[]、double[] 等。
MappedByteBuffer 用于实现内存映射文件,也不是本文存眷的重点。
我以为操纵 Buffer 和操纵数组、类集差不多,只不外大部门时候我们都把它放到了 NIO 的场景内里来利用罢了。下面先容 Buffer 中的几个重要属性和几个重要要领。
position、limit、capacity
就像数组有数组容量,每次会见元素要指定下标,Buffer 中也有几个重要属性:position、limit、capacity。
最好领略的虽然是 capacity,它代表这个缓冲区的容量,一旦设定就不行以变动。好比 capacity 为 1024 的 IntBuffer,代表其一次可以存放 1024 个 int 范例的值。一旦 Buffer 的容量到达 capacity,需要清空 Buffer,才气从头写入值。
position 和 limit 是变革的,我们别离看下读和写操纵下,它们是如何变革的。
position 的初始值是 0,每往 Buffer 中写入一个值,position 就自动加 1,代表下一次的写入位置。读操纵的时候也是雷同的,每读一个值,position 就自动加 1。
从写操纵模式到读操纵模式切换的时候(flip),position 城市归零,这样就可以从新开始读写了。
Limit:写操纵模式下,limit 代表的是最大能写入的数据,这个时候 limit 便是 capacity。写竣事后,切换到读模式,此时的 limit 便是 Buffer 中实际的数据巨细,因为 Buffer 不必然被写满了。
初始化 Buffer
每个 Buffer 实现类都提供了一个静态要领 allocate(int capacity)
辅佐我们快速实例化一个 Buffer。如:
ByteBuffer byteBuf = ByteBuffer.allocate(1024); IntBuffer intBuf = IntBuffer.allocate(1024); LongBuffer longBuf = LongBuffer.allocate(1024); // ...
别的,我们常常利用 wrap 要领来初始化一个 Buffer。
public static ByteBuffer wrap(byte[] array) { ... }
填充 Buffer
各个 Buffer 类都提供了一些 put 要领用于将数据填充到 Buffer 中,如 ByteBuffer 中的几个 put 要领:
// 填充一个 byte 值 public abstract ByteBuffer put(byte b); // 在指定位置填充一个 int 值 public abstract ByteBuffer put(int index, byte b); // 将一个数组中的值填充进去 public final ByteBuffer put(byte[] src) {...} public ByteBuffer put(byte[] src, int offset, int length) {...}
上述这些要领需要本身节制 Buffer 巨细,不能高出 capacity,高出会抛 java.nio.BufferOverflowException 异常。
对付 Buffer 来说,另一个常见的操纵中就是,我们要未来自 Channel 的数据填充到 Buffer 中,在系统层面上,这个操纵我们称为读操纵,因为数据是从外部(文件或网络等)读到内存中。
int num = channel.read(buf);
上述要了解返回从 Channel 中读入到 Buffer 的数据巨细。
提取 Buffer 中的值
前面先容了写操纵,每写入一个值,position 的值都需要加 1,所以 position 最后会指向最后一次写入的位置的后头一个,假如 Buffer 写满了,那么 position 便是 capacity(position 从 0 开始)。
假如要读 Buffer 中的值,需要切换模式,从写入模式切换到读出模式。留意,凡是在说 NIO 的读操纵的时候,我们说的是从 Channel 中读数据到 Buffer 中,对应的是对 Buffer 的写入操纵,初学者需要理清楚这个。
挪用 Buffer 的 flip() 要领,可以举办模式切换。其实这个要领也就是配置了一下 position 和 limit 值而已。
public final Buffer flip() { limit = position; // 将 limit 配置为实际写入的数据数量 position = 0; // 重置 position 为 0 mark = -1; // mark 之后再说 return this; }