【从入门到放弃-Java】并发编程-NIO-Buffer
前言
上篇【從入門到放棄-Java】并發編程-NIO-Channel中我們學習到channel是雙向通道,數據通過channel在實體(文件、socket)和緩沖區(buffer)中可以雙向傳輸。
本文我們就來學習下buffer
簡介
buffer即緩沖區,實際上是一塊內存,可以用來寫入、讀取數據。是一個線性的、大小有限的、順序承載基礎數據類型的內存塊。
buffer有三個重要的屬性:
- capacity:緩沖池大小,是不可變的。當buffer寫滿時,需要先清空才能繼續寫入。
- limit:是buffer中不可以被讀或者寫的第一個元素的位置,limit的大小永遠不會超過capacity(在寫模式下,limit等于capacity)
- position:是buffer中可以被讀或者寫的第一個元素的位置,position的大小永遠不會超過limit
除了boolean外,每一個基礎數據類型都有對應的buffer。如:ByteBuffer、CharBuffer、LongBuffer等
buffer不是線程安全的,如果要在多線程中使用 需要加鎖控制
接下來以ByteBuffer為例開始學習。
ByteBuffer
allocateDirect
public static ByteBuffer allocateDirect(int capacity) {//會創建一個容量大小為capacity的DirectByteBuffer(ByteBuffer的子類)return new DirectByteBuffer(capacity); }allocate
public static ByteBuffer allocate(int capacity) {if (capacity < 0)throw createCapacityException(capacity);//會創建一個容量大小為capacity的HeapByteBuffer(ByteBuffer的子類)return new HeapByteBuffer(capacity, capacity); }HeapByteBuffer和DirectByteBuffer的區別:
- DirectByteBuffer是直接調用native方法在本機os::malloc()創建堆外內存;HeapByteBuffer是直接在jvm的堆中分配內存。
- 當buffer中的數據和磁盤、網絡等的交互都在操作系統的內核中發生時,使用DirectByteBuffer能避免從內核態->用戶態->內核態的切換開銷,所有的處理都在內核中進行,性能會比較好
- 當頻繁創建操作數據量比較小的buffer時,使用HeapByteBuffer在jvm堆中分配內存能抵消掉使用DirectByteBuffer帶來的好處。
wrap
public static ByteBuffer wrap(byte[] array,int offset, int length) {try {return new HeapByteBuffer(array, offset, length);} catch (IllegalArgumentException x) {throw new IndexOutOfBoundsException();} }public static ByteBuffer wrap(byte[] array) {return wrap(array, 0, array.length);}將byte數組包裝成一個ByteBuffer
讀數據
- 使用get方法從Buffer中讀取數據
- 從Buffer中讀取數據到Channel即:Channel::write() (從buffer中讀取數據寫入到資源中,所以是write)
寫數據
- 使用put方法直接設置Buffer中的數據
- 從Channel中讀取數據到Buffer即:Channel::read() (從資源中讀取數據寫入到buffer中,所以是read)
position
//獲取buffer中當前position的位置 public final int position() {return position; }//設置buffer的position為newPosition,注意newPosition要大于0且小于limit,如果remark大于newPosition則設置為-1 public Buffer position(int newPosition) {if (newPosition > limit | newPosition < 0)throw createPositionException(newPosition);position = newPosition;if (mark > position) mark = -1;return this; }limit
//獲取buffer中當前limit的位置 public final int limit() {return limit; }//設置buffer的limit為newLimit,注意newLimit要大于0且小于capacity。如果position大于newLimit這設置為newLimit,如果remark大于newLimit則設置為-1 public Buffer limit(int newLimit) {if (newLimit > capacity | newLimit < 0)throw createLimitException(newLimit);limit = newLimit;if (position > limit) position = limit;if (mark > limit) mark = -1;return this; }mark
public Buffer mark() {//標記mark為當前positionmark = position;return this; }將當前位置做標記,在使用reset方法時,可以回到當前mark的位置
reset
public Buffer reset() {int m = mark;if (m < 0)throw new InvalidMarkException();//設置position為當前markposition = m;return this; }回到之前設置mark的位置
clear
public Buffer clear() {//設置position為0position = 0;//limit設置為capacity大小limit = capacity;//mark設置為-1(初始化)mark = -1;return this; }讀取完數據后調用clear,即將buffer邏輯上清空了,可以從0開始寫入數據
flip
public Buffer flip() {//limit設置為當前位置limit = position;//position設置為0position = 0;//mark設置為-1(初始化)mark = -1;return this; }將buffer從寫模式設置為讀模式,limit設置為當前position的位置,即只能讀取limit大小的數據
rewind
public Buffer rewind() {position = 0;mark = -1;return this; }將position設置為0,即從頭開始讀取
remaining
public final int remaining() {return limit - position; }返回buffer中還有多少byte是未讀的
hasRemaining
public final boolean hasRemaining() {return position < limit; }是否已讀完
compact
public ByteBuffer compact() {System.arraycopy(hb, ix(position()), hb, ix(0), remaining());position(remaining());limit(capacity());discardMark();return this; }將position和limit直接的數據copy到byteBuffer的起始處,將已讀數據清空,并將新的position設置為當前未讀數據的末尾。這樣能避免clear方法會將未讀數據也清空的問題
slice
public ByteBuffer slice() {return new HeapByteBufferR(hb,-1,0,this.remaining(),this.remaining(),this.position() + offset); }ByteBuffer slice(int pos, int lim) {assert (pos >= 0);assert (pos <= lim);int rem = lim - pos;return new HeapByteBufferR(hb,-1,0,rem,rem,pos + offset); }新創建一個ByteBuffer,將緩存區分片,設置一個子緩沖區,實際上內存還是共享的,數據發生改變,兩個緩沖區讀取的數據都會是改變后的。
總結
Buffer最重要的三個屬性:position、limit、capacity。牢記這三個屬性的含義及讀寫切換時,設置值是如何變化的,Buffer的核心知識點就掌握了。
原文鏈接
本文為云棲社區原創內容,未經允許不得轉載。
總結
以上是生活随笔為你收集整理的【从入门到放弃-Java】并发编程-NIO-Buffer的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何将深度学习训练速度提升一百倍?PAI
- 下一篇: AI赋能DevOps:数据驱动的全栈工程