本文转载自微信公众号“小明菜市场”,作者小明菜市场。转载本文请联系小明菜市场公众号。前言JavaNIO需要了解三个主要部分:buffer,channel,selector。为了提供稳定性,基本的用户空间和内核空间操作系统将虚拟地址空间分为用户空间和内核空间,其中用户进程只能操作用户空间的内容,而内核空间的内容可以操作内核空间的内容用户空间和用户空间的内容。I/O过程中的数据流向假设我们需要从磁盘上的某个文件中读取数据。进程发起read系统调用,进入内核态。然后内核会向磁盘控制硬件发出命令,请求它从磁盘中读取数据。磁盘控制器将数据直接写入内核缓冲区,然后内核将数据从内核空间的临时缓冲区复制到用户缓冲区,进程切换回用户态继续执行。总结数据流向为:Disk->KernelBuffer->UserBufferMemorySpaceMultipleMapping对于虚拟地址空间,可以有多个虚拟地址指向同一个物理内存地址。如果用户空间的虚拟地址和内核空间的虚拟地址映射到同一个物理地址,那么这个物理地址所代表的空间对内核和用户进程都是可见的。可以节省在内核缓冲区和用户缓冲区之间来回复制数据的开销。BufferJavaNIO数据传输过程,数据先放在发送缓冲区->通过通道发送到接收端->接收端通道收到数据后填充到接收缓冲区,所以缓冲区的作用是实际上是连接通道作为数据传输的目标或源。核心概念属性需要了解Buffer的工作机制。需要了解以下属性capacity:缓冲区的容量,创建缓冲区时指定位置:下一个要读取或写入的元素的索引的上界:缓冲区中第一个不能读取的位置或写给。mark标记,一个memopositionbuffer的核心在于访问操作,buffer提供了相对位置访问和绝对位置访问两种方式。相对位置访问:在当前位置写入或读取数据,然后增加该位置的值。绝对位置访问。在指定位置写入或读取数据而不改变位置的值。代码如下//相对位置访问publicabstractByteBufferput(byteb);publicabstractbyteget();//绝对位置访问publicabstractByteBufferput(intindex,byteb);publicabstractbyteget(intindex);flipping是buffer的核心概念,可以理解为buffer有两种模式,写模式和读模式。写入模式:在读取模式下,我们分配一个缓冲区并直接用数据填充它。我们从头开始读取数据。如何从写入模式切换到读取模式,翻转,翻转的时候我们用limit记录要读取的数据长度,然后把position替换为0开始读取数据。publicfinalBufferflip(){//记录要读取数据的长度limit=position;//从头开始读取数据position=0;mark=-1;returnthis;}demo//创建缓冲区ByteBufferbuffer=ByteBuffer.allocate(100);//写入数据for(charc:"hello".toCharArray()){buffer.put((byte)c);}//翻转buffer.flip();//相当于buffer.limit(buffer.position()).position(0);//读取数据while(buffer.hasRemaining()){charc=(char)buffer.get();System.out.println(c);}直接bufferforgeneralDuringI/O过程,数据流向为,磁盘或网络->内核临时缓冲区->用户空间缓冲区直接缓冲区解决了将内核空间临时缓冲区复制到用户空间缓冲区的冗余步骤。虽然直接缓冲区是I/O的最佳选择,但它比创建非直接缓冲区的成本更高,因此一般直接重用。创建缓冲区Buffer不能直接通过构造函数实例化,而是通过静态工厂方法创建,下面是ByteBuffer的静态工厂方法。//创建内存缓冲区publicstaticByteBufferallocate(intcapacity);//创建直接缓冲区publicstaticByteBufferallocateDirect(intcapacity);publicstaticByteBufferwrap(字节[]数组,intoffset,intlength)
