<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java NIO之緩沖區(qū)

          共 1102字,需瀏覽 3分鐘

           ·

          2020-10-10 23:34

          點擊上方藍色字體,選擇“標星公眾號”

          優(yōu)質(zhì)文章,第一時間送達

          ? 作者?|??油多壞不了菜

          來源 |? urlify.cn/JrAnIb

          66套java從入門到精通實戰(zhàn)課程分享

          最近打算把Java網(wǎng)絡編程相關的知識深入一下(IO、NIO、Socket編程、Netty)

          Java NIO主要需要理解緩沖區(qū)、通道、選擇器三個核心概念,作為對Java I/O的補充, 以提升大批量數(shù)據(jù)傳輸?shù)男省?/p>

          學習NIO之前最好能有基礎的網(wǎng)絡編程知識

          Java I/O流

          Java 網(wǎng)絡編程

          基礎

          除了需要對 Java 網(wǎng)絡編程有一定了解,還需要對用戶空間、內(nèi)核空間、內(nèi)存空間多重映射等知識有一定了解

          用戶空間與內(nèi)核空間

          為了提供操作系統(tǒng)的穩(wěn)定性,操作系統(tǒng)將虛擬地址空間分為用戶空間和內(nèi)核空間

          其中用戶進程(我們自己的程序)只能操作用戶空間

          I/O過程中的數(shù)據(jù)流向

          假設我們需要從磁盤中某個文件讀取數(shù)據(jù)。進程發(fā)起read()系統(tǒng)調(diào)用,進入內(nèi)核態(tài),內(nèi)核隨即向磁盤控制硬件發(fā)出命令, 要求其從磁盤讀取數(shù)據(jù),磁盤控制器將數(shù)據(jù)直接寫入到內(nèi)核內(nèi)存緩沖區(qū)中(這一步DMA完成,不需要CPU參與),隨后內(nèi)核把數(shù)據(jù)從內(nèi)核空間的臨時緩沖區(qū)拷貝到用戶緩沖區(qū)(需要CPU參與),進程切換回用戶態(tài)繼續(xù)執(zhí)行。

          總結(jié)起來的數(shù)據(jù)流向是:磁盤 ---> 內(nèi)核緩沖區(qū) ---> 用戶緩沖區(qū)

          那么問題來了:內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝到用戶緩沖區(qū)的這一步顯得有點多余,是否可以避免?

          內(nèi)存空間多重映射

          我們知道對于虛擬地址空間,一個以上的虛擬地址可指向同一個物理內(nèi)存地址

          如果把用戶空間的虛擬地址和內(nèi)核空間的虛擬地址映射到同一個物理地址,那么這塊物理地址代表的空間就對內(nèi)核和用戶進程都可見了??!便可省去數(shù)據(jù)在內(nèi)核緩沖區(qū)和用戶緩沖區(qū)來回復制的開銷。(這便是直接緩沖區(qū)的思想

          緩沖區(qū)(Buffer)

          Java NIO數(shù)據(jù)傳輸過程:數(shù)據(jù)先放到發(fā)送緩沖區(qū) --> 通過通道發(fā)送到接收端 ---> 接受端通道接受數(shù)據(jù)并填充到接受緩沖區(qū)

          所以緩沖區(qū)的作用其實是連接通道作為數(shù)據(jù)傳輸?shù)哪繕嘶蛘邅碓矗ɑ蛘哒f緩沖區(qū)是通道的輸入或者輸出)

          核心概念

          屬性

          要理解Buffer的工作機制,首先要了解幾個屬性的意義

          • capacity(容量) 緩沖區(qū)的容量,創(chuàng)建緩沖區(qū)時指定

          • position(位置)下一個要被讀取或者寫入的元素的索引

          • limit(上界)?緩沖區(qū)中第一個不能被讀或者寫的位置

          • mark(標記)一個備忘位置

            其中 mark <= position <= limit <= capacity,對limit和position兩個屬性的理解非常重要

          存取

          緩沖區(qū)的核心就在于存取操作,Buffer提供了相對位置存取和絕對位置存取兩種方式

          • 相對位置存取:在當前position位置寫入或者讀取數(shù)據(jù), 然后增加position的值

          • 絕對位置存?。涸谥付ǖ奈恢脤懭牖蛘咦x取數(shù)據(jù),不改變position的值

          ?//相對位置存取
          ?public?abstract?ByteBuffer?put(byte?b);
          ?public?abstract?byte?get();

          ?//絕對位置存取
          ?public?abstract?ByteBuffer?put(int?index,?byte?b);
          ?public?abstract?byte?get(int?index);

          翻轉(zhuǎn)(flip)

          翻轉(zhuǎn)是Buffer的核心概念,我們可以理解Buffer有兩種模式:寫模式和讀模式

          寫模式下,我們分配一個緩沖區(qū),然后直接填充數(shù)據(jù)(position的值從0開始遞增);讀模式下, 我們也從頭開始讀取數(shù)據(jù)(position從0開始遞增)

          那么我們怎么從寫模式切換到讀模式吶?翻轉(zhuǎn)!!翻轉(zhuǎn)的時候我們用limit記錄待讀取數(shù)據(jù)的長度, 然后將position置為0 就可以開始讀取數(shù)據(jù)了

          下為翻轉(zhuǎn)的源碼

          public?final?Buffer?flip()?{
          ???//記錄待讀取數(shù)據(jù)的長度
          ????limit?=?position;
          ???//從頭開始讀取數(shù)據(jù)
          ????position?=?0;
          ????mark?=?-1;
          ????return?this;
          }

          demo

          一個完整的例子

          //創(chuàng)建一個緩沖區(qū)?
          ByteBuffer?buffer?=?ByteBuffer.allocate(100);
          //寫數(shù)據(jù)
          for?(char?c?:?"hello".toCharArray())?{
          ??buffer.put((byte)?c);
          }
          //翻轉(zhuǎn)
          buffer.flip();//等價于?buffer.limit(buffer.position()).position(0);
          //讀數(shù)據(jù)
          while?(buffer.hasRemaining())?{
          ??char?c?=?(char)?buffer.get();
          ??System.out.println(c);
          }

          創(chuàng)建緩沖區(qū)

          Buffer不能直接通過構(gòu)造函數(shù)實例化,都是通過靜態(tài)工廠方法來創(chuàng)建。下為ByteBuffer的靜態(tài)工廠方法

          //創(chuàng)建內(nèi)存緩沖區(qū)
          public?static?ByteBuffer?allocate(int?capacity);
          //創(chuàng)建直接緩沖區(qū)
          public?static?ByteBuffer?allocateDirect(int?capacity)?;

          public?static?ByteBuffer?wrap(byte[]?array,?int?offset,?int?length)

          直接緩沖區(qū)(DirectByteBuffer)

          對于一般的I/O過程,數(shù)據(jù)的流向總是:磁盤或者網(wǎng)絡 --> 內(nèi)核臨時緩沖區(qū) --> 用戶空間緩沖區(qū),其中內(nèi)核空間臨時緩沖區(qū)到用戶空間緩沖區(qū)復制這一步顯得有點多余??!

          直接緩沖區(qū)解決了這個問題, 直接緩沖區(qū)對內(nèi)核和用戶空間都可見,這樣就可以避免"內(nèi)核臨時緩沖區(qū)到用戶空間緩沖區(qū)"復制的開銷

          雖然直接緩沖區(qū)是I/O的最佳選擇,但是其比創(chuàng)建非直接緩沖區(qū)花費更大的成本,所以我們對直接緩沖區(qū)一般都會重復使用(每次使用都創(chuàng)建的話成本就太高了)。

          總結(jié)

          本文主要講解NIO學習需要掌握的一些基礎知識以及緩沖區(qū)的使用,重點是對直接緩沖區(qū)的理解。



          粉絲福利:Java從入門到入土學習路線圖

          ???

          ?長按上方微信二維碼?2 秒


          感謝點贊支持下哈?

          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产日韩亚洲欧美精品在线播放 | 91无码成人视频 | 成人AAAAAA片 | 国产熟女乱伦 | 在线免费看黄 |