- ?談及Java NIO瞒大,最核心的三個(gè)組件就是
-
Channel
通道 -
ByteBuffer
讀寫緩沖區(qū) -
Selector
多路復(fù)用器
-
- 核心之一就是在對(duì)
ByteBuffer
的讀寫操作上。
ByteBuffer
為NIO中的字節(jié)緩沖區(qū),相對(duì)于BIO
的Stream
流只支持寫入或者讀取單向操作,ByteBuffer
是雙向的,支持讀和寫。
-
類型
-
DirectByteBuffer
- 使用的是操作系統(tǒng)級(jí)別的內(nèi)存,分配比較慢份名,但是數(shù)據(jù)的讀寫比較快,因?yàn)樯倭艘淮螐南到y(tǒng)內(nèi)存到JVM內(nèi)存的復(fù)制過(guò)程
- 初始化方法:
ByteBuffer.allocateDirect(1024 * 4);
-
HeapByteBuffer
- 使用的是JVM的堆內(nèi)存妓美,對(duì)于JVM來(lái)說(shuō)僵腺,分配比較快,但是讀寫比較慢壶栋,因?yàn)樾枰獙⒉僮飨到y(tǒng)內(nèi)存里的數(shù)據(jù)復(fù)制到JVM內(nèi)存
- 初始化方法:
ByteBuffer.allocate(1024 * 4);
-
-
核心屬性
-
capacity
-
ByteBuffer
的容量辰如,這個(gè)值在ByteBuffer
初始化的時(shí)候就確定下來(lái)了。不論是在讀還是在寫模式下贵试,這個(gè)值都不變琉兜。
-
-
position
- 寫模式下:
- 該值表示當(dāng)前寫到了
ByteBuffer
的哪個(gè)位置,ByteBuffer
初始化時(shí)毙玻,這個(gè)值為0豌蟋。 -
position
的最大值為capacity-1
。
- 該值表示當(dāng)前寫到了
- 讀模式下:
- 當(dāng)從寫模式切換到讀模式桑滩,會(huì)將
position
重置為0梧疲,即從ByteBuffer
的起始位置開(kāi)始讀取數(shù)據(jù)。
- 當(dāng)從寫模式切換到讀模式桑滩,會(huì)將
- 寫模式下:
-
limit
- 寫模式下:
-
limit
為最大可寫入的數(shù)據(jù)量运准,即ByteBuffer
的最大容量往声,值為capacity
-
- 讀模式下:
- 當(dāng)從寫模式切換從讀模式,
limit
將會(huì)被設(shè)置為讀模式下的position
值戳吝,即可讀取的最大數(shù)據(jù)量。
- 當(dāng)從寫模式切換從讀模式,
- 寫模式下:
-
-
核心方法
-
flip()
- 將寫模式切換為讀模式
- 會(huì)觸發(fā)的對(duì)核心屬性的操作:
- 將
position
設(shè)置為0
贯涎,即從ByteBuffer
起始位置開(kāi)始讀听哭。 - 將
limit
設(shè)置為寫模式下position
的值,即最大可讀取的數(shù)據(jù)量大小。
- 將
-
mark()
- 標(biāo)記當(dāng)前
position
位置
- 標(biāo)記當(dāng)前
-
reset()
- 將
position
指向上一次mark()
所指向的位置陆盘,可以從這個(gè)位置重復(fù)向下讀取數(shù)據(jù)
- 將
-
clear()
- 在邏輯上清空ByteBuffer里的數(shù)據(jù)普筹,實(shí)際上不清空數(shù)據(jù)
- 會(huì)觸發(fā)的動(dòng)作:
- 將
limit
設(shè)置為capacity
-
position
指向起始位置0
- 提示:實(shí)際上數(shù)據(jù)并未清理,只是下次是從0的位置開(kāi)始寫入數(shù)據(jù)隘马,效果上像是數(shù)據(jù)清空了太防。
- 提示:如果
ByteBuffer
中的數(shù)據(jù)并未完全讀完,調(diào)用這個(gè)方法將忽略那些未讀取的數(shù)據(jù)酸员。
- 將
-
compact()
- 如果并未讀取完
ByteBuffer
中的數(shù)據(jù)蜒车,調(diào)用compact()
會(huì)將position~limit
之間的數(shù)據(jù)拷貝到ByteBuffer
的起始處,并且position
為剩余數(shù)據(jù)量的大小幔嗦,下次再往ByteBuffer
中寫入數(shù)據(jù)時(shí)酿愧,將在position
位置繼續(xù)往下寫,不會(huì)覆蓋歷史數(shù)據(jù)邀泉。
- 如果并未讀取完
-
hasRemaining()
- 判斷緩沖區(qū)中是否還有未讀數(shù)據(jù)
-
-
將數(shù)據(jù)寫入ByteBuffer的方式
byteBuffer.put(x)
channel.read(byteBuffer)
-
從ByteBuffer中讀取數(shù)據(jù)的方式
byteBuffer.get()
channel.write(bytebuffer)
# 代碼演示
/**
* ByteBuffer的代碼演示
*
* @author futao
* @date 2020/7/7
*/
public class ByteBufferDemo {
public static void main(String[] args) {
// ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024 * 4);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 4);
// Q: 初始化之后嬉挡,這三個(gè)值分別是多少呢?
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
//向ByteBuffer寫入數(shù)據(jù)
byteBuffer.put("hello, 喜歡天文的pony站長(zhǎng)~".getBytes(Constants.CHARSET));
// Q: 向ByteBuffer中寫入數(shù)據(jù)之后汇恤,哪些值會(huì)發(fā)生變化呢庞钢?
System.out.println(StringUtils.repeat("=", 10) + "寫入數(shù)據(jù)之后" + StringUtils.repeat("=", 10));
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
//將ByteBuffer從寫模式調(diào)整為讀模式
byteBuffer.flip();
//將ByteBuffer從寫模式調(diào)整為讀模式之后,ByteBuffer的哪些值會(huì)發(fā)生變化因谎?
System.out.println(StringUtils.repeat("=", 10) + "調(diào)整ByteBuffer為讀模式之后" + StringUtils.repeat("=", 10));
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
//從ByteBuffer中讀取一個(gè)字節(jié)
byteBuffer.get();
// Q: 從ByteBuffer中讀取一個(gè)字節(jié)之后基括,哪些值會(huì)發(fā)生變化?
System.out.println(StringUtils.repeat("=", 10) + "從ByteBuffer中讀取一個(gè)字節(jié)之后" + StringUtils.repeat("=", 10));
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
// 記錄一個(gè)標(biāo)記
byteBuffer.mark();
// 繼續(xù)往下讀取
byteBuffer.get();
System.out.println(StringUtils.repeat("=", 10) + "記錄一個(gè)標(biāo)記之后繼續(xù)往下讀取" + StringUtils.repeat("=", 10));
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
//重置position到上一次mark()的標(biāo)記位置
byteBuffer.reset();
System.out.println(StringUtils.repeat("=", 10) + "reset之后" + StringUtils.repeat("=", 10));
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
System.out.println("byteBuffer中是否還有數(shù)據(jù):" + byteBuffer.hasRemaining());
//拷貝未讀取的數(shù)據(jù)到緩沖區(qū)最前面
byteBuffer.compact();
System.out.println(StringUtils.repeat("=", 10) + "compact之后" + StringUtils.repeat("=", 10));
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
//邏輯上清空數(shù)據(jù)=>實(shí)際上只是指針的變化
byteBuffer.clear();
System.out.println(StringUtils.repeat("=", 10) + "clear之后" + StringUtils.repeat("=", 10));
System.out.println("position: " + byteBuffer.position());
System.out.println("capacity: " + byteBuffer.capacity());
System.out.println("limit: " + byteBuffer.limit());
}
}
- 先不要看結(jié)果,自己思考一下喲蓝角,邏輯還是很清晰的~
是不是與你思考的一致~
# 源代碼
- 源代碼都給你了你還不看看?
# 系列文章
- 【BIO】在聊天室項(xiàng)目中的演化
- 【BIO】通過(guò)指定消息大小實(shí)現(xiàn)的多人聊天室-終極版本
- 【BIO】基于BIO實(shí)現(xiàn)簡(jiǎn)單動(dòng)態(tài)HTTP服務(wù)器
歡迎在評(píng)論區(qū)留下你看文章時(shí)的思考阱穗,及時(shí)說(shuō)出,有助于加深記憶和理解使鹅,還能和像你一樣也喜歡這個(gè)話題的讀者相遇~