Buffer

  1. Java NIO Buffer
    当我们需要与NIO Channel进行交互时,我们就需要使用到NIO Buffer,即数据从Buffer读取到Channel中,并且从Channel中写入到Buffer中。
    实际上,一个Buffer其实就是一块内存区域,我们可以在这个内存区域中进行数据的读写。NIO Buffer其实是这样的内存块的一个封装,并提供了一些操作方法让我们能够方便地进行数据的读写。
  2. Buffer类型有:
  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer
  1. NIO Buffer的基本使用
    使用NIO Buffer的步骤如下:
  • 将数据写入Buffer中

  • 调用Buffer.flip()方法,将NIO Buffer转换为读模式

  • 从Buffer中读取数据

  • 调用Buffer.clear()或Buffer.compact()方法,将Buffer转换为写模式。
    当我们将数据写入到Buffer中时,Buffer会记录我们已经写了多少的数据,当我们需要从Buffer中读取数据时,必须调用Buffer.flip()将Buffer切换为度模式。
    一旦读取了所有的Buffer数据,那么我们必须清理Buffer,让其从新可写,清理Buffer可以调用Buffer.clear()或Buffer.compact()

    public class Test {
        public static void main(String[] args) {
        IntBuffer intBuffer = IntBuffer.allocate(2);
        intBuffer.put(124342);
        intBuffer.put(3);
       intBuffer.flip();
      System.out.println(intBuffer.get());
      System.out.println(intBuffer.get());
      }
    }
    

分配了两个单位大小的IntBuffer,因此他可以写入两个int值
我们使用put方法将int值写入,然后使用flip方法将buffer转换为读模式,然后连续使用get方法从buffer中获取这两个int值。
没当调用一次get方法读取数据时,buffer的读指针就会向前移动一个单位长度(在这里是一个int长度)。

  1. Buffer属性
    一个Buffer由三个属性:
  • capacity
  • position
  • limit
    其中position和limit的含义和Buffer处于读模式或写模式有关,而capacity的含义与Buffer所处的模式无关
  1. capacity
    一个内存块会有一个固定的大小,即容量(capacity),我们最多写入capacity个单位的数据到Buffer中,例如一个DoubleBuffer,其Capacity是100,那么我们做多可以写入100个double数据。

  2. position
    当从一个Buffer中写入数据时,我们是从Buffer的一个确定的位置(position)开始写入。在最初的状态时,position的值是0。每当我们写入了一个单位的数据后,position就会递增一。
    当我们从Buffer中读取数据时,我们也是从某个特定的位置开始读取。当我们调用了flip()方法将Buffer从写模式转换到读模式时,position的值会自动被设置为0,每当我们读取一个单位的数据,position的值递增1。
    position表示了读写操作的位置指针。

  3. limit
    limit-position表示此时还可以写入/读取多少单位的数据

  4. 分配Buffer
    为了获取一个Buffer对象,我们首先需要分配内存空间。每个类型的Buffer都有一个allocate()方法,我们可以通过这个方法分配Buffer

    ByteBuffer buf = ByteBuffer.allocate(48);
    

这里我们分配了48*sizeof(Byte)字节的内存空间

  1. 关于Direct Buffer和Non-Direct Buffer的区别
  • Direct Buffer:

    • 所分配的内存不在JVM堆上,不受GC的管理(但是Direct Buffer的java对象是由GC管理的,因此当发生GC,对象被回收时,Direct Buffer也会被释放)
    • 因为Direct Buffer不在JVM堆上分配,因此Direct Buffer对应用程序的内存占用的影响就不那么明显(实际上还是镇用了那么多内存,但是JVM不好统计到非JVM管理的内存)
    • 申请和释放Direct Buffer的开销比较大,因此正确的使用Direct Buffer的方式是在初始化时申请一个Buffer,然后不断复用此Buffer,在程序结束后才释放此Buffer
    • 使用Direct Buffer时,当进行一些底层的系统IO操作时,效率会比较高,因为此时JVM不需要拷贝buffer中的内存到中间临时缓冲区。
  • Non-Direct buffer

    • 直接在JVM堆上进行内存的分配,本质上市byte[]数组的封装
    • 因为Non-Direct Buffer在JVM堆中,因此当进行操作系统底层IO操作时,会将次Buffer的内存复制到中间临时缓冲区,因此Non-Direct buffer的效率就较低
  1. 写数据到Buffer

    int bytesRead = inChannel.read(buf); //read into buffer.
    buf.put(127);
    
  2. 从Buffer中读取数据

        //read from buffer into channel.
    int bytesWritten = inChannel.write(buf);
    byte aByte = buf.get();
    
  3. 重置position
    Buffer.rewind()方法可以重置position的值为0,因此我们可以重新读取/写入Buffer了,如果是读模式,则重置的是读模式的position,如果是写模式,则重置的是写模式的position

  4. mark()和reset()
    我么可以通过调用Buffer.mark()将当前的position的值保存起来,随后可以通过调用Buffer.reset()方法将position的值恢复回来

    public class Test {
    
             public static void main(String[] args) {
             IntBuffer intBuffer = IntBuffer.allocate(2);
             intBuffer.put(1);
             intBuffer.put(2);
    
            intBuffer.flip();
            System.out.println(intBuffer.get());
            intBuffer.mark();
            System.out.println(intBuffer.get());
    
           System.out.println(intBuffer.position());
           intBuffer.reset();
          System.out.println(intBuffer.position());
          System.out.println(intBuffer.get());
        }
    }
    

这里我们写入两个int值,然后首先读取了一个值,此时读position的值为1
接着我们调用mark()方法将当前的position保存起来(在读模式,因此保存的是position),然后再次读取,此时position就是2了,接着使用reset()恢复原来的读position,因此读position就为1,可以再次读取数据。

  1. flip,rewind和clear的区别
  • flip
    源码

    public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
    }
    

Buffer的读/写模式公用一个position和limit变量
当从写模式变为读模式时,原来的写position就变成了读模式的limit

  • rewind
    源码

     public final Buffer rewind() {
     position = 0;
      mark = -1;
      return this;
    }
    

rewind,即倒带,这个方法仅仅是将position置为0

  • clear
    源码

    public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
    }  
    

根据源码我们知道,clear将position设置为0,将limit设置为capacity
clear方法使用场景
1 在一个已经写满数据的Buffer中,调用clear,可以从头读取buffer的数据。
2 为了将一个Buffer填充慢数据,可以调用clear,然后一直写入,直到达到limit

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Java NIO中的Buffer用于和NIO通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的...
    AFinalStone阅读 276评论 0 0
  • Buffer java NIO库是在jdk1.4中引入的,NIO与IO之间的第一个区别在于,IO是面向流的,而NI...
    德彪阅读 2,176评论 0 3
  • 参考:http://ifeve.com/buffers/原文地址 目录 Java NIO教程 Java NIO 教...
    步积阅读 4,999评论 8 16
  • Java NIO中的Buffer用于和NIO通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的...
    bboymonk阅读 496评论 0 0
  • 我从博尔赫斯的一本书里了解到,A或C可能影响了B,又可以通过对B的预料或揣测到极远处存在着的Z,而B并不认识Z。这...
    老晁阅读 395评论 0 1