《精通併發與Netty》學習筆記(15 - 詳解NIO中Buffer之position,limit,capacity)

1、前言
熟悉NIO的人想必必定不會陌生buffer中position,limit,capacity這三個屬性吧,以前在學習的時候遇到一個問題:就是當你先往緩衝區寫入一部分數據,而後調用flip()方法,再所有讀取完數據,而後再調用flip()方法,此時這三個值的變化是怎樣的,研究了一下,決定寫下來分享一下。java

2、正文
一、介紹數組

position: 它指的是下一次讀取或寫入的位置。學習

limit: 指定還有多少數據須要寫出(在從緩衝區寫入通道時),或者還有多少空間能夠讀入數據(在從通道讀入緩衝區時),它初始化是與capacity的值同樣,當調用flip()方法以後,它的值會改變成position的值,而position被置0。它箭頭所指的位置是最後一位元素的下一位所在的位置*測試

capacity: 指定了能夠存儲在緩衝區中的最大數據容量,實際上,它指定了底層數組的大小,或者至少是指定了准許咱們使用的底層數組的容量,這個初始化後就不會再改變了。大數據

二、圖示this

以上三個屬性值之間有一些相對大小的關係:0 <= position <= limit <= capacity。若是咱們建立一個新的容量大小爲7的ByteBuffer對象,在初始化的時候,position設置爲0,limit和 capacity被設置爲7,在之後使用ByteBuffer對象過程當中,capacity的值不會再發生變化,而其它兩個個將會隨着使用而變化。三個屬性值分別如圖所示:spa

初始化:3d

 

假設咱們如今要往這個緩衝區裏面寫入3個字節,寫完以後,position的箭頭就會指向3的位置,而limit不變:code

     

此時咱們想從緩衝區讀取這3個字節,就必須調用flip()方法,調用了flip()方法事後,limit置爲position的位置,而position被置爲0,也正應證了上面所說的,position它指的是下一次讀取或寫入的位置,limit它箭頭所指的位置是最後一位元素的下一位所在的位置:對象

 

如今咱們能夠調用get()方法,一直從緩衝區裏面取數據,直到取完爲止,也就是當position與limit的值同樣時,就取完了:   

 
這一次簡單的讀寫操做就完成了,若是想恢復成初始狀態的話,能夠調用clear()方法:

以前學到這裏的時候有個疑問,不知道你們想過沒有,就是咱們在調用了get()方法從緩衝區取完裏面的數據,立馬去調用flip()方法,那這三個屬性的值會是什麼變化?若是當我只讀了2個字節的數據以後,就不讀了,而後再去調用flip(),這三個值又會是怎麼變化?其實無論怎麼繞,你只要懂得原理,就不難,我們先看flip()源代碼作了什麼:

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

這裏不難發現,調用flip()方法,無非就是給這幾個變量賦值,將當前的position值賦給limit,而後將position的值置爲0,Mark是一個標誌變量,我們之後會提到。熟悉以上代碼就不難解決我提出的2個問題:

當你讀取完調用flip()的方法 positon:0 limit:3 capacity:7
當你讀取2個字節以後調用flip()方法 positon:0 limit:2 capacity:7

這裏就解決了我以前遇到的這三個屬性值變化的問題!!!

3、測試代碼
讀取完調用flip:

package com.cing.nio;

import java.io.FileInputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NioTest1 {
public static void main(String[] args) throws Exception{

FileInputStream fis = new FileInputStream("D:\\A.txt");
FileChannel fc = fis.getChannel();

ByteBuffer buffer = ByteBuffer.allocate(7);
output("初始化", buffer);

fc.read(buffer);
output("調用READ方法", buffer);

buffer.flip();
output("第一次調用flip", buffer);

while (buffer.remaining() > 0) {
byte b = buffer.get();
}
output("get()", buffer);

buffer.flip();
output("第二次flip", buffer);

fis.close();
}

public static void output(String step, Buffer buffer) {
System.out.println(step + " : ");
System.out.println("buffer: " + buffer + ", ");
}
}

輸出結果爲:

初始化 : 
buffer: java.nio.HeapByteBuffer[pos=0 lim=7 cap=7], 
調用READ方法 : 
buffer: java.nio.HeapByteBuffer[pos=3 lim=7 cap=7], 
第一次調用flip : 
buffer: java.nio.HeapByteBuffer[pos=0 lim=3 cap=7], 
get() : 
buffer: java.nio.HeapByteBuffer[pos=3 lim=3 cap=7], 
第二次flip : 
buffer: java.nio.HeapByteBuffer[pos=0 lim=3 cap=7], 

讀取2字節以後調用flip:

package com.cing.nio;

import java.io.FileInputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NioTest1 {
public static void main(String[] args) throws Exception{

FileInputStream fis = new FileInputStream("D:\\A.txt");
FileChannel fc = fis.getChannel();

ByteBuffer buffer = ByteBuffer.allocate(7);
output("初始化", buffer);

fc.read(buffer);
output("調用READ方法", buffer);

buffer.flip();
output("第一次調用flip", buffer);

while (buffer.remaining() > 1) {
byte b = buffer.get();
}
output("get()", buffer);

buffer.flip();
output("第二次flip", buffer);

fis.close();
}

public static void output(String step, Buffer buffer) {
System.out.println(step + " : ");
System.out.println("buffer: " + buffer + ", ");
}
}

輸出結果爲:

初始化 : 
buffer: java.nio.HeapByteBuffer[pos=0 lim=7 cap=7], 
調用READ方法 : 
buffer: java.nio.HeapByteBuffer[pos=3 lim=7 cap=7], 
第一次調用flip : 
buffer: java.nio.HeapByteBuffer[pos=0 lim=3 cap=7], 
get() : 
buffer: java.nio.HeapByteBuffer[pos=2 lim=3 cap=7], 
第二次flip : 
buffer: java.nio.HeapByteBuffer[pos=0 lim=2 cap=7],
相關文章
相關標籤/搜索