日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NIO 之 ByteBuffer实现原理

發布時間:2024/9/30 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NIO 之 ByteBuffer实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

相關文章

IO、NIO、AIO 內部原理分析
NIO 之 Selector實現原理
NIO 之 Channel實現原理

前言

Java NIO 主要由下面3部分組成:

  • Buffer
  • Channel
  • Selector

在傳統IO中,流是基于字節的方式進行讀寫的。
在NIO中,使用通道(Channel)基于緩沖區數據塊的讀寫。

流是基于字節一個一個的讀取和寫入。
通道是基于塊的方式進行讀取和寫入。

Buffer 類結構圖

Buffer 的類結構圖如下:

從圖中發現java中8中基本的類型,除了boolean外,其它的都有特定的Buffer子類。

Buffer類分析

Filed

每個緩沖區都有這4個屬性,無論緩沖區是何種類型都有相同的方法來設置這些值

private int mark = -1; private int position = 0; private int limit; private int capacity;

1. 標記(mark)

初始值-1,表示未標記。
標記一個位置,方便以后reset重新從該位置讀取數據。

public final Buffer mark() {mark = position;return this; }public final Buffer reset() {int m = mark;if (m < 0)throw new InvalidMarkException();position = m;return this; }

2. 位置(position)

緩沖區中讀取或寫入的下一個位置。這個位置從0開始,最大值等于緩沖區的大小

//獲取緩沖區的位置 public final int position() {return position; } //設置緩沖區的位置 public final Buffer position(int newPosition) {if ((newPosition > limit) || (newPosition < 0))throw new IllegalArgumentException();position = newPosition;if (mark > position) mark = -1;return this; }

3. 限度(limit)

//獲取limit位置 public final int limit() {return limit; } //設置limit位置 public final Buffer limit(int newLimit) {if ((newLimit > capacity) || (newLimit < 0))throw new IllegalArgumentException();limit = newLimit;if (position > limit) position = limit;if (mark > limit) mark = -1;return this;}

4. 容量(capacity)

緩沖區可以保存元素的最大數量。該值在創建緩存區時指定,一旦創建完成后就不能修改該值。

//獲取緩沖區的容量 public final int capacity() {return capacity; }

filp 方法

public final Buffer flip() {limit = position;position = 0;mark = -1;return this; }
  • 將limit設置成當前position的坐標
  • 將position設置為0
  • 取消標記
  • rewind 方法

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

    從源碼中發現,rewind修改了position和mark,而沒有修改limit。
    1. 將position設置為0
    2. 取消mark標記

    clear 方法

    public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this;}
  • 將position坐標設置為0
  • limit設置為capacity
  • 取消標記
  • 從clear方法中,我們發現Buffer中的數據沒有清空,如果通過Buffer.get(i)的方式還是可以訪問到數據的。如果再次向緩沖區中寫入數據,他會覆蓋之前存在的數據。

    remaining 方法

    查看當前位置和limit之間的元素數。

    public final int remaining() {return limit - position; }

    hasRemaining 方法

    判斷當前位置和limit之間是否還有元素

    public final boolean hasRemaining() {return position < limit; }

    ByteBuffer 類分析

    從圖中我們可以發現 ByteBuffer繼承于Buffer類,ByteBuffer是個抽象類,它有兩個實現的子類HeapByteBuffer和MappedByteBuffer類

    HeapByteBuffer:在堆中創建的緩沖區。就是在jvm中創建的緩沖區。
    MappedByteBuffer:直接緩沖區。物理內存中創建緩沖區,而不在堆中創建。

    allocate 方法(創建堆緩沖區)

    public static ByteBuffer allocate(int capacity) {if (capacity < 0)throw new IllegalArgumentException();return new HeapByteBuffer(capacity, capacity); }

    我們發現allocate方法創建的緩沖區是創建的HeapByteBuffer實例。

    HeapByteBuffer 構造

    HeapByteBuffer(int cap, int lim) { // package-privatesuper(-1, 0, lim, cap, new byte[cap], 0); }

    從堆緩沖區中看出,所謂堆緩沖區就是在堆內存中創建一個byte[]數組。

    allocateDirect創建直接緩沖區

    public static ByteBuffer allocateDirect(int capacity) {return new DirectByteBuffer(capacity); }

    我們發現allocate方法創建的緩沖區是創建的DirectByteBuffer實例。

    DirectByteBuffer構造


    直接緩沖區是通過java中Unsafe類進行在物理內存中創建緩沖區。

    wrap 方法

    public static ByteBuffer wrap(byte[] array) public static ByteBuffer wrap(byte[] array, int offset, int length);

    可以通過wrap類把字節數組包裝成緩沖區ByteBuffer實例。
    這里需要注意的的,把array的引用賦值給ByteBuffer對象中字節數組。如果array數組中的值更改,則ByteBuffer中的數據也會更改的。

    get 方法

  • public byte get()
    獲取position坐標元素,并將position+1;
  • public byte get(int i)
    獲取指定索引下標的元素
  • public ByteBuffer get(byte[] dst)
    從當前position中讀取元素填充到dst數組中,每填充一個元素position+1;
  • public ByteBuffer get(byte[] dst, int offset, int length)
    從當前position中讀取元素到dst數組的offset下標開始填充length個元素。
  • put 方法

  • public ByteBuffer put(byte x)
    寫入一個元素并position+1
  • public ByteBuffer put(int i, byte x)
    指定的索引寫入一個元素
  • public final ByteBuffer put(byte[] src)
    寫入一個自己數組,并position+數組長度
  • public ByteBuffer put(byte[] src, int offset, int length)
    從一個自己數組的offset開始length個元素寫入到ByteBuffer中,并把position+length
  • public ByteBuffer put(ByteBuffer src)
    寫入一個ByteBuffer,并position加入寫入的元素個數
  • 視圖緩沖區


    ByteBuffer可以轉換成其它類型的Buffer。例如CharBuffer、IntBuffer 等。

    壓縮緩沖區

    public ByteBuffer compact() {System.arraycopy(hb, ix(position()), hb, ix(0), remaining());position(remaining());limit(capacity());discardMark();return this;}

    1、把緩沖區positoin到limit中的元素向前移動positoin位
    2、設置position為remaining()
    3、 limit為緩沖區容量
    4、取消標記

    例如:ByteBuffer.allowcate(10);
    內容:[0 ,1 ,2 ,3 4, 5, 6, 7, 8, 9]

    compact前

    [0 ,1 ,2 , 3, 4, 5, 6, 7, 8, 9]
    pos=4
    lim=10
    cap=10

    compact后

    [4, 5, 6, 7, 8, 9, 6, 7, 8, 9]
    pos=6
    lim=10
    cap=10

    slice方法

    public ByteBuffer slice() {return new HeapByteBuffer(hb,-1,0,this.remaining(),this.remaining(),this.position() + offset); }

    創建一個分片緩沖區。分配緩沖區與主緩沖區共享數據。
    分配的起始位置是主緩沖區的position位置
    容量為limit-position。
    分片緩沖區無法看到主緩沖區positoin之前的元素。

    直接緩沖區和堆緩沖區性能對比

    下面我們從緩沖區創建的性能和讀取性能兩個方面進行性能對比。

    讀寫性能對比

    public static void directReadWrite() throws Exception {int time = 10000000;long start = System.currentTimeMillis();ByteBuffer buffer = ByteBuffer.allocate(4*time);for(int i=0;i<time;i++){buffer.putInt(i);}buffer.flip();for(int i=0;i<time;i++){buffer.getInt();}System.out.println("堆緩沖區讀寫耗時 :"+(System.currentTimeMillis()-start));start = System.currentTimeMillis();ByteBuffer buffer2 = ByteBuffer.allocateDirect(4*time);for(int i=0;i<time;i++){buffer2.putInt(i);}buffer2.flip();for(int i=0;i<time;i++){buffer2.getInt();}System.out.println("直接緩沖區讀寫耗時:"+(System.currentTimeMillis()-start)); }

    輸出結果:

    堆緩沖區創建耗時 :70 直接緩沖區創建耗時:47

    從結果中我們發現堆緩沖區讀寫比直接緩沖區讀寫耗時更長。

    #

    public static void directAllocate() throws Exception {int time = 10000000;long start = System.currentTimeMillis();for (int i = 0; i < time; i++) {ByteBuffer buffer = ByteBuffer.allocate(4);}System.out.println("堆緩沖區創建時間:"+(System.currentTimeMillis()-start));start = System.currentTimeMillis();for (int i = 0; i < time; i++) {ByteBuffer buffer = ByteBuffer.allocateDirect(4);}System.out.println("直接緩沖區創建時間:"+(System.currentTimeMillis()-start)); }

    輸出結果:

    堆緩沖區創建時間:73 直接緩沖區創建時間:5146

    從結果中發現直接緩沖區創建分配空間比較耗時。

    對比結論

    直接緩沖區比較適合讀寫操作,最好能重復使用直接緩沖區并多次讀寫的操作。
    堆緩沖區比較適合創建新的緩沖區,并且重復讀寫不會太多的應用。

    建議:如果經過性能測試,發現直接緩沖區確實比堆緩沖區效率高才使用直接緩沖區,否則不建議使用直接緩沖區。

    本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8????
    點擊這里快速進入簡書

    GIT地址:http://git.oschina.net/brucekankan/
    點擊這里快速進入GIT

    總結

    以上是生活随笔為你收集整理的NIO 之 ByteBuffer实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久久久久久国产精品 | 午夜剧场91 | 波多野结衣 一区 | 久久中文字幕在线 | 天天综合天天 | 成人日韩精品 | 三男一女吃奶添下面 | 无码国产精品高潮久久99 | 青青草国内自拍 | 欧美精品电影一区二区 | 97综合视频 | 日韩欧美一二三四区 | 狠狠干夜夜 | 少妇被躁爽到高潮 | 一区二区三区四区影院 | 狠狠躁18三区二区一区 | 在线视频91 | 国产精品久久久久久在线观看 | 李宗瑞91在线正在播放 | 日韩精品在线视频免费观看 | 久久久久久久综合色一本 | 天天视频入口 | 亚洲字幕av| 国产不卡视频在线观看 | 欧美日本韩国在线 | 久色成人| 男人和女人做爽爽视频 | 超碰2| 99国产免费 | 毛片自拍 | 最新高清无码专区 | 成年人午夜 | 国产av天堂无码一区二区三区 | 成人免费看片&#39; | 一个人看的毛片 | av电影中文字幕 | 草草影院一区二区三区 | 欧美在线xxxx| 午夜福利三级理论电影 | 国产区一二三 | 亚洲一卡二卡 | 人人澡澡人人 | 免费精品 | 97自拍偷拍 | 久久久久久天堂 | 国产剧情在线视频 | 中文亚洲av片在线观看 | 超碰免费在线97 | av在线不卡一区 | 激情影音| 91精品国产乱码久久久久久久久 | 狠狠操在线播放 | 欧美激情999 | 91看片就是不一样 | 黑巨茎大战欧美白妞 | 日本视频h | 污网站在线观看免费 | 天天操夜夜操视频 | 国产亚洲一区二区在线 | 日本韩国欧美 | 亚州春色| 福利精品视频 | 女人18毛片毛片毛片毛片区二 | 欧美在线网| 国产馆在线观看 | 国产成人亚洲综合 | 成人污污www网站免费丝瓜 | 久久精品国产99 | 激情五月激情综合 | 欧美伦理一区二区三区 | youjizz.com国产| 国产日韩欧美一区二区东京热 | 老司机精品视频在线播放 | 日韩av免费看 | 国产欧美一区二区视频 | 免费黄色高清视频 | 欧美色图片区 | 爱的色放3 | 伊人开心网 | 在线观看你懂的视频 | 牛牛超碰 | 亚洲人一区 | 精品无码av一区二区三区四区 | 18做爰免费视频网站 | 中文字幕乱妇无码av在线 | 四虎网址在线观看 | 免费成人美女女电影 | 人人人人爽 | 黄色aaa视频| 欧美人体做爰大胆视频 | 欧美性一区二区三区 | 欧美激情一区二区三区蜜桃视频 | 日韩一区二区影视 | 在线观看波多野结衣 | av鲁丝一区鲁丝二区鲁丝三区 | 91大片在线观看 | 性欧美大战久久久久久久免费观看 | 国产第一页视频 | 女性裸体下面张开 |