上篇【從入門到放棄-Java】併發編程-NIO-Channel中咱們學習到channel是雙向通道,數據經過channel在實體(文件、socket)和緩衝區(buffer)中能夠雙向傳輸。html
本文咱們就來學習下buffer編程
buffer即緩衝區,其實是一塊內存,能夠用來寫入、讀取數據。是一個線性的、大小有限的、順序承載基礎數據類型的內存塊。數組
buffer有三個重要的屬性:緩存
除了boolean外,每個基礎數據類型都有對應的buffer。如:ByteBuffer、CharBuffer、LongBuffer等安全
buffer不是線程安全的,若是要在多線程中使用 須要加鎖控制網絡
接下來以ByteBuffer爲例開始學習。多線程
public static ByteBuffer allocateDirect(int capacity) { //會建立一個容量大小爲capacity的DirectByteBuffer(ByteBuffer的子類) return new DirectByteBuffer(capacity); }
public static ByteBuffer allocate(int capacity) { if (capacity < 0) throw createCapacityException(capacity); //會建立一個容量大小爲capacity的HeapByteBuffer(ByteBuffer的子類) return new HeapByteBuffer(capacity, capacity); }
HeapByteBuffer和DirectByteBuffer的區別:併發
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數組包裝成一個ByteBufferjvm
//獲取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; }
//獲取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; }
public Buffer mark() { //標記mark爲當前position mark = position; return this; }
將當前位置作標記,在使用reset方法時,能夠回到當前mark的位置socket
public Buffer reset() { int m = mark; if (m < 0) throw new InvalidMarkException(); //設置position爲當前mark position = m; return this; }
回到以前設置mark的位置
public Buffer clear() { //設置position爲0 position = 0; //limit設置爲capacity大小 limit = capacity; //mark設置爲-1(初始化) mark = -1; return this; }
讀取完數據後調用clear,即將buffer邏輯上清空了,能夠從0開始寫入數據
public Buffer flip() { //limit設置爲當前位置 limit = position; //position設置爲0 position = 0; //mark設置爲-1(初始化) mark = -1; return this; }
將buffer從寫模式設置爲讀模式,limit設置爲當前position的位置,即只能讀取limit大小的數據
public Buffer rewind() { position = 0; mark = -1; return this; }
將position設置爲0,即從頭開始讀取
public final int remaining() { return limit - position; }
返回buffer中還有多少byte是未讀的
public final boolean hasRemaining() { return position < limit; }
是否已讀完
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方法會將未讀數據也清空的問題
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的核心知識點就掌握了。
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。