源码解析-JavaNIO之Buffer,Channel

NIO: New IO / Native IO 

jdk1.4诞生出来的,优化了传统IO的拷贝次数

(重点在 不再需要内核缓冲区,用户缓冲区与JVM内存之间的频繁拷贝

直接创建一块堆外内存,直接映射对应的磁盘物理地址,然后通过虚拟地址缺页中断,切换到内核直接将物理地址加载到堆外内存,一次拷贝都不需要 四舍五入相当于堆外内存直接打通磁盘了)

 

Buffer

 

 

 抽象类,抽象理解为在JVM内存开辟一块空间,用作缓冲数据。Buffer实际理解为就是一个数组,可以存储byte类型数据。

几个重要属性:capacity, position, limit    

capacity: 就是buffer的最大值  如果任何操作超过了这个值直接抛 java.nio.BufferOverflowException 异常

position: 每读一个值 或者每写入一个值,position+1

limit: 限制当前可操作的最大值

mark: 做标记,标记一下当前position的位置,方便以后可以回到这个地方重读(reset操作)

 

实际的操作分为读写两种

读操作 每读一个值position+1, limit为当前数据实际长度,也就是可读的最大长度

写操作 每写入一个值position+1,limit = capacity,也就是可写入的最大长度

 核心继承关系

Buffer:抽象类,负责来来回回操作那四个属性 capacity, position, limit,mark

ByteBuffer: 抽象类,真正的创建了数组 final byte[] hb, 以后实际用来存放字节数据的就是hb,定义了put(),get()等读写缓冲区的方法

HeapByteBuffer: 实现类,直接创建JVM堆中字节缓存空间

MappedByteBuffer: 抽象类,创建了堆外缓存空间,直接映射一块磁盘物理地址。  force()方法,强制将缓冲区数据写入磁盘物理地址

DirectByteBuffer: MappedByteBuffer的实现类

 

Buffer的主要功能很简单,put() 一下数据、flip() 切换到读模式、然后用 get() 获取数据、clear() 一下清空数据、重新回到 put() 写入数据。

重要意义在于开辟了对外空间直接映射磁盘物理地址这一骚操作, 想了解操作系统级底层图可以参考一下子 https://www.cnblogs.com/ttaall/p/14128788.html

 

Channel

Channel的意思是一个管道,说是一个管道其实更像是目的地。比如物理磁盘的地址目的地,

MappedByteBuffer开创了一块堆外内存,FileChannel找到磁盘文件物理位置,就可以直接把buffer传给channel, 从而实现把buffer中的数据写到channel,从channel读数据到buffer中

 nio包下重点关注的Channel继承关系

FileChannel: 文件通道,用于文件的读和写

SocketChannel: 把它理解为 TCP 连接通道,简单理解就是 TCP 客户端

ServerSocketChannel: TCP 对应的服务端,用于监听某个端口进来的请求

DatagramChannel: 用于 UDP 连接的接收和发送

 

FileChannel 写入实现

 

1. 第一部分获取Channel  

getChannel()  

 发现了吗,单例模式懒汉式 ,直接来对象锁,如果channel为null创建 

FileChannelImpl.open(); 

FileChannel实现了两个open()方法,区别是什么呢?

都调用了new FileChannelImpl()  只是传的第五个参数不同,上边的方法直接写死了传的false

 var3 是否可读 var4 是否可写 var5 是否可追加

FileInputStream  实现的 可读,不可写,不可追加

FileOutPutStram  实现的  可读,可写,能否追加取决于创建FileOutPutStram的时候咋实现的,默认是false

 

2. 第二部分开辟Buffer

ByteBuffer抽象类的静态方法 allocateDirect()  参数就是创建buffer的字节大小(话说抽象父类具有子类的创建方式,这... 难道说就因为DirectByteBuffer设计成了default的,就要通过父类的静态方法new了吗?)

DirectByteBuffer的 put方法实现底层就是这个了,通过unsafe类把字节put出去

 刷新一下,将limit设置为当前数据大小,重置一下position为0 重置一下mark为-1

 

read() write()的方法就不看了,底层都是调用native本地库,估计是c语言的类库来读写的

 

posted @ 2020-12-17 15:45  六小扛把子  阅读(201)  评论(0编辑  收藏  举报