圖解java中的bytebuffer


  1. 因何而寫

    網上關於bytebuffer的文章真的很多,為何在此還要寫一篇呢?主要是基於以下幾點考慮
    1. 很多人在使用t-io時,還不會bytebuffer,只會照着t-io提供的例子照貓畫虎,不利於靈活運用
    2. 網上搜到的一些相關文章,講得不是太易懂,不利於初學者靈活運用bytebuffer
    3. 本文旨在講解靈活運用bytebuffer所需的最小知識,以幫助用戶快速掌握bytebuffer
  2. 用極易的方式認識一下bytebuffer

    1. bytebuffer之第一眼印象

      我們可以把bytebuffer理解成如下幾個成員組成的一個新對象,對,就是一個普通的java對象,像string一樣的java對象。(強調一下,這里只是說這樣理解,實際上有些bytebuffer的實現類並非這樣實現,並且這里只列出掌握bytebuffer所需要的最小知識集合,其它諸如mark等字段本文並不介紹,以免增加初學者的惑度
      1. byte[] bytes: 用來存儲數據
      2. int capacity: 用來表示bytes的容量,那么可以想像capacity就等於bytes.size(),此值在初始化bytes后,是不可變的。
      3. int limit: 用來表示bytes實際裝了多少數據,可以容易想像得到limit <= capacity,此值是可靈活變動的
      4. int position: 用來表示在哪個位置開始往bytes寫數據或是讀數據,此值是可靈活變動的
      通過下圖,對bytebuffer形成一個感觀認識吧
    2. bytebuffer之常用操作及各操作對內部變量帶來的變化

      1. 創建bytebuffer: ByteBuffer.allocate(6)

      2. 寫入一個字節: byteBuffer.put((byte)3)

      3. 讀取一個字節: byte bs = byteBuffer.get()

        對於剛剛寫好的bytebuffer,我們要讀取它的內容,需要先設置一下position和limit,否則讀的位置就不對
        
        byteBuffer.position(0);  //設置position到0位置,這樣讀數據時就從這個位置開始讀
        byteBuffer.limit(1);     //設置limit為1,表示當前bytebuffer的有效數據長度是1
        
        我們看一下,設置position和limit后,bytebuffer的內部變化

        接下來,我們就可以讀取剛才寫入的數據了
        
        byte bs = byteBuffer.get();
        

    3. bytebuffer之使用心得

      這里說的是作者本人使用bytebuffer的一些心得,這些與其說是心得,不如說是實踐+測試得來的一些經驗,所以並不保證就是權威的,歡迎有更深研究的朋友來合理討論,如果有不同意見,可以以更好的論據來說服對方。
      1. HeapByteBuffer.get(byte[], int, int)效率不如 System.arraycopy()

        前者實現的原理是用for循環來做的,后者是內存復制,t-io一般是用后者來做bytebuffer的組合,譬如SendRunnable.java的下面這段代碼
        
        ByteBuffer allByteBuffer = ByteBuffer.allocate(allBytebufferCapacity);
        byte[] dest = allByteBuffer.array();
        for (ByteBuffer byteBuffer : byteBuffers) {
        	if (byteBuffer != null) {
        		int length = byteBuffer.limit();
        		int position = allByteBuffer.position();
        		System.arraycopy(byteBuffer.array(), 0, dest, position, length);
        		allByteBuffer.position(position + length);
        	}
        }
        
        注意:如果DirectBuffer並不能用System.arraycopy來代替get(byte[], int, int),因為這貨的內部實現不是byte[]的
      2. jdk自帶的bytebuffer已經足夠好用

        有一些nio/aio框架喜歡自己弄一套bytebuffer來,既增加了作者自己的工作量,又增加了用戶的學習成本,但我們要知道一點,nio/aio在發送數據時,最終的參數是jdk的bytebuffer,我們真的有必要再作一次轉換和計算嗎?盡管某些中間過程是“零拷貝”(這個“零拷貝”也是有額外的計算成本的)的,但是jdk版bytebuffer的誕生到發送完畢,這整個過程經歷了哪些操作呢?真的是如某書某博客上所說的“零拷貝”嗎?更不應該把某些對象池的做法也牽強附會到“零拷貝”的概念中來----對象池屬對象重復利用范疇,既然是重復利用自然便已經默認有零拷貝的屬性了,但是對象池本身的維護也是需要消耗資源的,所以並不是所有場景說用了對象池,性能就提升了,有時候用不好反而增加負擔,所以萬事要以測試數據為准,不應盲目人雲亦雲!
  3. 最后附上bytebuffer的示例程序

    這里附上bytebuffer的示例程序,用戶可以自己debug觀察觀察,增加bytebuffer的相關概念,以便更靈活的運用bytebuffer
    
    import java.nio.ByteBuffer;
    
    /** * @author tanyaowu * 2017年5月1日 上午9:00:50 */
    public class Ts {
    
    	/** * * @author: tanyaowu */
    	public Ts() {
    	}
    
    	/** * @param args * @author: tanyaowu */
    	public static void main(String[] args) {
    		ByteBuffer byteBuffer = ByteBuffer.allocate(6);
    		byteBuffer.put((byte)3);
    		
    		byteBuffer.position(0);  //設置position到0位置,這樣讀數據時就從這個位置開始讀
    		byteBuffer.limit(1);     //設置limit為1,表示當前bytebuffer的有效數據長度是1
    		
    		byte bs = byteBuffer.get();
    		System.out.println(byteBuffer);
    	}
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM