Java 入门总结(三) —— NIO
Buffer
1、在 Java 中,已有的 IO 操作大部分都属于阻塞的操作。为了提升服务器操作的性能,在 JDK1.4 之后增加了 NIO,在整个 NIO 的操作中,基本上都是使用缓冲区完成的。
2、public abstract class Bufferextends Object
抽象类 Buffer 是一个用于特定基本类型数据的容器。
3、缓冲区是特定基本类型元素的线性有限序列。除内容外,缓冲区的基本属性还包括容量、限制和位置:
缓冲区的 容量(capacity) 是它所包含的元素的数量。缓冲区的容量不能为负并且不能更改。
缓冲区的 限制(limit) 是第一个不应该读取或写入的元素的索引。缓冲区的限制不能为负,并且不能大于其容量。
缓冲区的 位置(position) 是下一个要读取或写入的元素的索引。缓冲区的位置不能为负,并且不能大于其限制。
对于每个非 boolean 基本类型,此类都有一个子类与之对应。
4、标记、位置、限制和容量值遵守以下不变式: 0 <= 标记 <= 位置 <= 限制 <= 容量
。
5、清除、反转和重绕
clear() 使缓冲区为一系列新的通道读取或相对放置 操作做好准备:它将限制设置为容量大小,将位置设置为 0。
flip() 使缓冲区为一系列新的通道写入或相对获取 操作做好准备:它将限制设置为当前位置,然后将位置设置为 0。
rewind() 使缓冲区为重新读取已包含的数据做好准备:它使限制保持不变,将位置设置为 0。
6、直接 与 非直接缓冲区
字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
直接字节缓冲区可以通过调用此类的 allocateDirect 工厂方法来创建。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。
直接字节缓冲区还可以通过 mapping 将文件区域直接映射到内存中来创建。Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。
字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理。
Channel
1、在 NIO 中,通道是一个可以用来读取和写入数据的一种形式。Channel 接口,用于 I/O 操作的连接。通道表示到实体的开放连接。 通道表示到实体,如硬件设备、文件、网络套接字或可以执行一个或多个不同 I/O 操作(如读取或写入)的程序组件的开放的连接。通道都是通过操作缓冲区来完成全部功能的。所有的内容都是先读或写到缓冲区之中,再通过缓冲区读或写入到通道中的,即程序不会直接操作通道。
2、Java NIO Channel 通道和流非常相似,主要有以下几点区别:
通道可以读也可以写,流一般来说是单向的(只能读或者写)。
通道可以异步读写。
通道总是基于缓冲区Buffer来读写。
3、什么是内存映射?
将文件中的某个区域直接映射到内存中;对于较大的文件,这通常比调用普通的 read 或 write 方法更为高效。 在通道中还有一种方式成为内存映射。内存映射是速度最快的,MapperedByteBuffer,使用此种方式读取的内容是最快的,需要将一个输入的操作流绑定在内存映射上。
内存映射在读取的时候是最快的,但是如果执行的是写入操作则有可能是非常危险的,因为仅仅只是改变数组中的单个元素这样简单的操作就可能直接修改磁盘上的文件,因为修改数据与将数据保存在磁盘上是一样的。
文件锁
在 Java NIO 中提供了文件锁的功能,这样当一个线程将文件锁定之后,其他线程是无法操作此文件的,要想进行文件的锁定操作,则要使用 FileLock 类完成,此类的对象需要依靠 FileChannel 进行实例化操作。
锁定方式:
共享锁:允许多个线程进行文件的读取操作。
独占锁:只允许一个线程进行文件的读/写操作。