java io buffer状态_Java高效NIO之Java IO基础

本文详细介绍了Java的NIO模型,包括传统的IO模型与NIO模型的区别。NIO的核心组件包括Selector、Channel和Buffer。Selector用于多路复用IO,Channel是数据处理的入口,Buffer则提供数据缓存。文章还详细阐述了Buffer的Capacity、Position和Limit三个关键参数的含义及其在读写模式下的变化。
摘要由CSDN通过智能技术生成

Java中有两套IO模型,分别是传统IO和JDK1.4新引入的NIO(叫New IO或 Non-Blocking IO,后者更能体现它的设计理念)。

在传统IO模型中,网络IO是基于数据流(Stream)的,数据的输入和输出分别对应InputStream和OutputStream。流数据只能逐字节的读取(或写入),直到所有数据读取(或写入)完毕,流数据只能单向的读取(或写入),无缓存区,无法对数据进行前后移动访问。

在NIO模型中,网络IO是基于Channel和IO多路复用技术,实现原理更接近OS的IO模型,网络读IO的两阶段模型(数据准备、数据拷贝)中,数据准备阶段是Non-Blocking的,Channel和Buffer配合主要处理的是数据拷贝阶段的工作。

传统IO模式,在处理数据流过程中,线程处于阻塞状态,直到流处理(读取后写入)完毕,所以一个线程只能处理一个IO任务,如果IO未准备就绪无数据(或不可写)线程只能一直等待,直到可以有数据(或可写);

NIO模式,采用IO多路复用技术,使用选择器(Selector)监控一组IO,虽然Selector线程也处于阻塞状态,但一个线程可以同时处理多个IO任务,当IO就绪时,Selector返回就绪的IO并由程序进行处理。

1b872a89abf14aa20bd83fed682ac896.png

NIO核心设计

如上图所示,NIO的核心涉及3部分,分别为Selector、Channel和Buffer。在描述数据读写操作时,需要特别注意读写的主体,从Channel的角度,读数据是指把数据从Channel读取数据写入Buffer,写数据是指把Buffer的数据写入Channel;从Buffer的角度,写数据是指把数据写入Buffer,读数据是指从Buffer中读取数据写入Channel或转换为其他数据类型。

Selector

Selector是NIO多理复用的执行组件,系统在处理多个IO任务时,可以把每个IO任务以Channel的方式注册到Selector,通过Selector.select()统一监控向其注册的Channel的状态,select()方法会阻塞,直到其中有Channel的IO状态准备就绪有数据可读(或IO可写)时,select()返回就绪IO的Channel由程序处理相关事件。

Selector只能监听SelectableChannel类型的Channel,主要应用场景为网络IO等数据准备阶段时间较长的IO,SocketChannel属于此类型,而FileChannel不属于。

10178d50c9a8d8b9b04fe26a1aed31aa.png

Selector的主要方法:

open():静态方法,创建Selector对象

select():查询IO准备就绪的Channel

Channel

Channel是NIO中数据处理的入口,每个Channel对应着一个IO的底层数据Buffer,负责对Buffer的写入或读取操作。根据IO类型不同,Java中提供了如下通用Channel实现。

FileChannel:文件读写操作

SocketChannel:TCP Socket连接

ServerSocketChannel:TCP Socket服务器端,处理监听端口建立Socket的accept事件

DatagramChannel:UDP连接

SocketChannel的主要方法:

register():向Selector注册Channel感兴趣的事件,事件包括:

OP_ACCEPT:ServerSocketChannel收到客户端连接事件

OP_CONNECT:客户端连接服务器成功事件

OP_READ:Channel收到数据,可读事件

OP_WRITE:Channel可写事件

open():静态方法,建立Socket Channel通道

read():从Channel中读取数据,写入Buffer

write():把Buffer中数据写入Channel

map():把Channel中部分数据或者全部数据映射成MappedByteBuffer

当Socket关闭后,会触发对端的OP_READ事件,但此时read()返回-1或throw IOexception,可以通过这两个判断来确定对端是否关闭,并调用close()方法关闭SocketChannel并执行清理工作。

Buffer

Buffer本质上是一块连续的内存区域,提供数据缓存功能和Channel对数据的读写操作能力。NIO提供了 ByteBuffer / CharBuffer / DoubleBuffer / FloatBuffer / IntBuffer / LongBuffer / ShortBuffer Buffer类型,实现读Java基本类型的缓存支持。对Buffer的读写操作过程中,涉及3个关键参数,即postion、limit和capacity。其中position和limit在读/写操作时具有不同的意义,而capacity读写时都是表示Buffer的大小。Buffer初始处于写状态,数据写入后,通过flip切换的读取状态,读取完后,再通过clear清除数据,准备写入。

e4034b77f2f0e11b5d7328e3f383fff8.png

Capacity

Buffer是一个固定大小的内存缓存区,Capacity就表示其总长度。向Buffer写入的数据字节(byte/char/int/long等)总长度不能超过Capacity。当Buffer写满时,需要(读取)清空后才能继续写入。

Position

Position初始位置为0,当Buffer读写模式切换时,也会自动重置为0。

读取模式时,Position表示当前读取数据的位置,读取当前位置数据后,Position自动移到下一个可读位置,读取位置不能超过Limit。

写入模式时,Position表达当前写入数据的位置,在当前位置写入数据后,Position自动移到下一个写入位置,写入位置不能超过Capacity - 1。

Limit

读模式时,Limit表示Buffer中可读取数据长度,当Buffer从写模式切换到读模式时,Limit值等于写模式时的Position。

写模式时,Limit表示可写入数据总长度,其值等于Capacity - 1。

Buffer的主要方法:

allocate():静态方法,分配Buffer空间

allocateDirect():静态方法,分配Native堆Buffer空间

flip():调整position和limit到读取数据状态

clear():清空数据,为再次写入数据准备

rewind():设置position为0,重置读取位置

put()/get():写入和读取数据

public final Buffer flip() {

limit = position;

position = 0;

mark = -1;

return this;

}

public final Buffer clear() {

position = 0;

limit = capacity;

mark = -1;

return this;

}

public final Buffer rewind() {

position = 0;

mark = -1;

return this;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值