zoukankan      html  css  js  c++  java
  • 源码解析-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语言的类库来读写的

  • 相关阅读:
    洛谷P1501 动态树(LCT)
    Beijing Institute of Technology 2019.6 Monthly Contest (For grade 2018)
    [BJOI2018]求和
    [JSOI2015]最小表示
    简单题
    [Ynoi2016]掉进兔子洞
    乘积
    飞扬的小鸟
    [CTSC2008]网络管理
    Sequence
  • 原文地址:https://www.cnblogs.com/ttaall/p/14150058.html
Copyright © 2011-2022 走看看