【NIO】NIO三劍客之一ByteBuffer介紹與使用

  • ?談及Java NIO瞒大,最核心的三個(gè)組件就是
    • Channel 通道
    • ByteBuffer 讀寫緩沖區(qū)
    • Selector 多路復(fù)用器
  • 核心之一就是在對(duì)ByteBuffer的讀寫操作上。

ByteBuffer為NIO中的字節(jié)緩沖區(qū),相對(duì)于BIOStream流只支持寫入或者讀取單向操作,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)從寫模式切換到讀模式桑滩,會(huì)將position重置為0梧疲,即從ByteBuffer的起始位置開(kāi)始讀取數(shù)據(jù)。
    • limit
      • 寫模式下:
        • limit為最大可寫入的數(shù)據(jù)量运准,即ByteBuffer的最大容量往声,值為capacity
      • 讀模式下:
        • 當(dāng)從寫模式切換從讀模式,limit將會(huì)被設(shè)置為讀模式下的position值戳吝,即可讀取的最大數(shù)據(jù)量。
  • 核心方法

    • flip()
      • 將寫模式切換為讀模式
      • 會(huì)觸發(fā)的對(duì)核心屬性的操作:
        • position設(shè)置為0贯涎,即從ByteBuffer起始位置開(kāi)始讀听哭。
        • limit設(shè)置為寫模式下position的值,即最大可讀取的數(shù)據(jù)量大小。
    • mark()
      • 標(biāo)記當(dāng)前position位置
    • 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é)果,自己思考一下喲蓝角,邏輯還是很清晰的~
image.png

是不是與你思考的一致~

# 源代碼

# 系列文章

歡迎在評(píng)論區(qū)留下你看文章時(shí)的思考阱穗,及時(shí)說(shuō)出,有助于加深記憶和理解使鹅,還能和像你一樣也喜歡這個(gè)話題的讀者相遇~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末揪阶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子患朱,更是在濱河造成了極大的恐慌鲁僚,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裁厅,死亡現(xiàn)場(chǎng)離奇詭異冰沙,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)执虹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門拓挥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人袋励,你說(shuō)我怎么就攤上這事侥啤〉卑龋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵盖灸,是天一觀的道長(zhǎng)蚁鳖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赁炎,這世上最難降的妖魔是什么醉箕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮徙垫,結(jié)果婚禮上讥裤,老公的妹妹穿的比我還像新娘。我一直安慰自己松邪,他們只是感情好坞琴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著逗抑,像睡著了一般剧辐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邮府,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天荧关,我揣著相機(jī)與錄音,去河邊找鬼褂傀。 笑死忍啤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仙辟。 我是一名探鬼主播同波,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叠国!你這毒婦竟也來(lái)了未檩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤粟焊,失蹤者是張志新(化名)和其女友劉穎冤狡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體项棠,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悲雳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了香追。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片合瓢。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖透典,靈堂內(nèi)的尸體忽然破棺而出晴楔,到底是詐尸還是另有隱情迁央,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布滥崩,位于F島的核電站,受9級(jí)特大地震影響讹语,放射性物質(zhì)發(fā)生泄漏钙皮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一顽决、第九天 我趴在偏房一處隱蔽的房頂上張望短条。 院中可真熱鬧,春花似錦才菠、人聲如沸茸时。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)可都。三九已至,卻和暖如春蚓耽,著一層夾襖步出監(jiān)牢的瞬間渠牲,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工步悠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留签杈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓鼎兽,卻偏偏與公主長(zhǎng)得像答姥,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谚咬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354