Java NIO

Java NIO

资料来源

定义

NIO即new IO

我们可以将它想象成一个煤矿,Channel(通道)是一个包含煤层(数据)的矿藏,而 Buffer(缓冲器)则是派送到矿藏的卡车。卡车满载煤炭而归,我们再从卡车上获得煤炭。也就是说,我们并没有直接和 Channel 交互;我们只是和 Buffer 交互,并把 Buffer 派送到 Channel。Channel 要么从 Buffer 获得数据,要么向 Buffer 发送数据。

新特性

基于通道、缓冲区操作通道(Channel):一个新的IO模型.缓冲区(Buffer):为所有基本数据类型(除了boolean)提供缓冲支持
非阻塞提供多路复用IO
选择器用于单线程监听多个通道的事件

Buffer

在这里插入图片描述

核心参数

  • capacity:它表示一个 Buffer 包含的元素数量,它是非负且恒定不变的。
  • position:它是下一个要读或者写的元素的索引,它是非负的且不会超过 limit 的大小。
  • limit:它是可以读或者写的最后一个元素的索引,它是非负的且不会超过 capacity 的大小。
  • mark:当调用 reset() 方法被调用时,一个 Buffer 的 mark 值会被设定为当前的 position 值的大小。

0 <= mark <= position <= limit <= capacity

Buffer的读模式和写模式的区分

Buffer的本身不区分读写,随意我们可以利用position和limit区分

position=limit时是写,不等于时是读

读写模式的转换

  • clear( ) :调用 clear( ) 方法后,我们就可以向 Buffer 里面 put 数据,或者 Channel 能读取 Buffer 里的数据,并且将 limit 设置为 capacity,将 position 设置为 0。
  • flip( ) :调用 flip( ) 方法后,我们就可以向 Buffer 里面 get 数据,或者 Channel 能向 Buffer 里写数据,并且将 limit 设置为 position,将 position 设置为 0。
  • rewind( ) :调用 flip( ) 方法后,使 Buffer 里的数据可以被重新读取(无论是我们从 Buffer 读,还是 Channel 从 Buffer 读),此时 limit 不变,将 position 设置为 0。

Buffer分类

Heap

Heap存在于JVM堆上,这部分内存的回收和普通对象一样.Heap类型的Buffer对象都包含一个对应基本数据类型的数组属性,数组才是Heap类型的底层缓冲区.但是Heap类型的Buffer不能作为缓冲区参数直接进行系统调用,主要原因如下:

  • JVM在GC是可能会移动缓冲区(复制-整理),缓冲区的地址不固定
  • 系统调用时,缓冲区需要是连续的,但是数组不可能是连续的(JVM的实现没要求连续)

Heap类型的Buffer进行IO时,JVM需要产生一个临时Direct类型的Buffer,然后进行数据复制,再使用临时Direct的Buffer作为参数进行操作系统调用。这造成很低的效率,主要是因为两个原因:

  • 需要把数据从Heap类型的Buffer里面复制到临时创建的Direct的Buffer里面。
  • 可能产生大量的Buffer对象,从而提高GC的频率。所以在IO操作时,可以通过重复利用Buffer进行优化。

Direct

Direct类型的buffer,不存在于堆上,而是JVM通过malloc直接分配的一段连续的内存,这部分内存成为直接内存,JVM进行IO系统调用时使用的是直接内存作为缓冲区。
-XX:MaxDirectMemorySize,通过这个配置可以设置允许分配的最大直接内存的大小(MappedByteBuffer分配的内存不受此配置影响)。
直接内存的回收和堆内存的回收不同,如果直接内存使用不当,很容易造成OutOfMemoryError。JAVA没有提供显示的方法去主动释放直接内存,sun.misc.Unsafe类可以进行直接的底层内存操作,通过该类可以主动释放和管理直接内存。同理,也应该重复利用直接内存以提高效率。

线程安全性

Buffer不是线程安全的

Channel

public static void main(String[] args) throws Exception {
    FileOutputStream fileOutputStream = new FileOutputStream("/Users/wangleshan/Desktop/json/test.json");
    FileChannel channel = fileOutputStream.getChannel();
    byte[] bytes = "HelloNIO".getBytes(StandardCharsets.UTF_8);
    channel.write(ByteBuffer.wrap(bytes));
    fileOutputStream.close();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值