Java NIO中的Buffer
簡介
Buffer緩沖區,首先要弄明白的是,緩沖區是怎樣一個概念。它其實是緩存的一種,我們常說的緩存,包括保存在硬盤上的瀏覽器緩存,保存在內存中的緩存(比如Redis、memcached)。Buffer是把數據保存在內存中,它本質上用來保存數據的數據結構是數組,例如ByteBuffer是byte數組,IntBuffer是int數組等,對Buffer讀寫操作,其實是對該數組進行數據存放、讀取、清除操作。
Buffer可以理解成是一個容器,可以往容器里寫入數據,也可以從容器中讀取數據,可以一個字節一個字節的讀寫,也可以多個字節讀寫,可以在寫的途中切換為讀,讀到一半又切換到寫,等等。。。
Buffer有以下幾個屬性:
- int mark 標記
- int position 位置
- int limit限制
- int capacity緩沖區的容量,Buffer的容量是固定的,在創建Buffer對象時,制定容量大小。
這幾個屬性,有什么作用,用在什么地方,為何設置這4個屬性。其實不用先理解,在了解reset(),flip()等方法后,就會明白這四個屬性的用處。
主要方法
mark、reset
- mark() 在Buffer當前的位置設置標記
public final Buffer mark() {mark = position;return this; }
- reset() 重置Buffer當前的位置為上一次的標記
public final Buffer reset() {int m = mark;if (m < 0)throw new InvalidMarkException();position = m;return this; }
這兩個方法的使用場景,從Buffer讀取n個字節數據,結果讀出來的數據長度比n小(比如網絡是拆包問題),這時候會重新再讀一次,調用reset()方法。但并不是所有讀操作是從位置0開始讀,所以在reset()先設置一個標記,調用mark(),最后position = mark,就是從標記的mark位置開始讀。
clear,flip, rewind
- clear() 清除Buffer
public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this; }
- flip() 反轉Buffer,何謂“反轉”?在執行完寫操作之后,調用調用flip()為下次的讀操作準備。
public final Buffer flip() {limit = position;position = 0;mark = -1;return this; }
使用場景:在進行完寫操作后,寫入100個字節,所以當前位置position=100,為了下次讀操作,讀出來是這100個字節數據,所以limit也設為100,限制最多讀到100個字節。下次讀是從位置0開始,所以position=0。
ByteBuffer buffer = ByteBuffer.allocate(100); String value = "zhangxh20"; buffer.put(value.getBytes()); buffer.flip(); byte [] arr = new byte[buffer.remaining()]; buffer.get(arr); String decodeValue = new String(arr);
看下調用flip()操作前后的對比。
如果不做flip操作,讀到的將是position到capacity之間的錯誤內容。
當執行flip()操作之后,它的limit被設置為position,position設置為0,capacity不變,由于讀取的內容是從position到limit之間,因此,他能夠正確讀取到之前寫入緩沖區的內容。
- rewind() 重繞Buffer,可以發現rewind()比flip()少了個步驟limit = positon。
public final Buffer rewind() {position = 0;mark = -1;return this; }
使用場景:buffer.get(array),把buffer的數據復制到array數組里,會調用buffer的get()方法。get()是從position開始復制,最多limit個,所以只需positon設置為0。
其他特性
不變式
標記、位置、限制和容量值遵守以下不變式:
0 <= 標記 <= 位置 <= 限制 <= 容量
新創建的緩沖區總有一個 0 位置和一個未定義的標記。初始限制可以為 0,也可以為其他值,這取決于緩沖區類型及其構建方式。一般情況下,緩沖區的初始內容是未定義的。
線程安全
Buffer不是線程安全的,被多個線程使用時,需要加同步。
ByteBuffer
byteBuffer字節緩沖區,即每次調用get()或者put()操作的數據最小單位是byte,理IntBuffer、LongBuffer、DoubleBuffer以此類推。例如LongBuffer put()最小的單位是8個字節的long數據。日常開發中,ByteBuffer使用的會比較多,其他類型Buffer很少使用。
事實上ByteBuffer也可以用來表示其他類型Buffer,比如IntBuffer的get(),可以用ByteBuffer的getInt(),兩個實現效果一樣。
堆內存和直接內存
Buffer在創建時,必須指定容量大小,還有分配內存的類型,有兩種堆內存和直接內存,直接可以理解為堆外的內存空間,區別就是,直接內存是不受GC管理
參考資料
- 《Netty權威指南》
轉載于:https://www.cnblogs.com/zhangxh20/p/7163863.html
總結
以上是生活随笔為你收集整理的Java NIO中的Buffer的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摅字开头的四字成语有哪些?
- 下一篇: 洛谷—— P1118 [USACO06F