国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java NIO 的前生今世 之三 NIO Buffer 詳解

madthumb / 2848人閱讀

摘要:當我們需要與進行交互時我們就需要使用到即數(shù)據(jù)從讀取到中并且從中寫入到中實際上一個其實就是一塊內(nèi)存區(qū)域我們可以在這個內(nèi)存區(qū)域中進行數(shù)據(jù)的讀寫其實是這樣的內(nèi)存塊的一個封裝并提供了一些操作方法讓我們能夠方便地進行數(shù)據(jù)的讀寫類型有這些覆蓋了能從中傳

Java NIO Buffer

當我們需要與 NIO Channel 進行交互時, 我們就需要使用到 NIO Buffer, 即數(shù)據(jù)從 Buffer讀取到 Channel 中, 并且從 Channel 中寫入到 Buffer 中.
實際上, 一個 Buffer 其實就是一塊內(nèi)存區(qū)域, 我們可以在這個內(nèi)存區(qū)域中進行數(shù)據(jù)的讀寫. NIO Buffer 其實是這樣的內(nèi)存塊的一個封裝, 并提供了一些操作方法讓我們能夠方便地進行數(shù)據(jù)的讀寫.
Buffer 類型有:

ByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer
這些 Buffer 覆蓋了能從 IO 中傳輸?shù)乃械?Java 基本數(shù)據(jù)類型.

NIO Buffer 的基本使用

使用 NIO Buffer 的步驟如下:

將數(shù)據(jù)寫入到 Buffer 中.

調(diào)用 Buffer.flip()方法, 將 NIO Buffer 轉(zhuǎn)換為讀模式.

從 Buffer 中讀取數(shù)據(jù)

調(diào)用 Buffer.clear() 或 Buffer.compact()方法, 將 Buffer 轉(zhuǎn)換為寫模式.

當我們將數(shù)據(jù)寫入到 Buffer 中時, Buffer 會記錄我們已經(jīng)寫了多少的數(shù)據(jù), 當我們需要從 Buffer 中讀取數(shù)據(jù)時, 必須調(diào)用 Buffer.flip()將 Buffer 切換為讀模式.
一旦讀取了所有的 Buffer 數(shù)據(jù), 那么我們必須清理 Buffer, 讓其從新可寫, 清理 Buffer 可以調(diào)用 Buffer.clear() 或 Buffer.compact().
例如:

public class Test {
    public static void main(String[] args) {
        IntBuffer intBuffer = IntBuffer.allocate(2);
        intBuffer.put(12345678);
        intBuffer.put(2);
        intBuffer.flip();
        System.err.println(intBuffer.get());
        System.err.println(intBuffer.get());
    }
}

上述中, 我們分配兩個單位大小的 IntBuffer, 因此它可以寫入兩個 int 值.
我們使用 put 方法將 int 值寫入, 然后使用 flip 方法將 buffer 轉(zhuǎn)換為讀模式, 然后連續(xù)使用 get 方法從 buffer 中獲取這兩個 int 值.
每當調(diào)用一次 get 方法讀取數(shù)據(jù)時, buffer 的讀指針都會向前移動一個單位長度(在這里是一個 int 長度)

Buffer 屬性

一個 Buffer 有三個屬性:

capacity

position

limit
其中 position limit 的含義與 Buffer 處于讀模式或?qū)懩J接嘘P(guān), 而 capacity 的含義與 Buffer 所處的模式無關(guān).

Capacity

一個內(nèi)存塊會有一個固定的大小, 即容量(capacity), 我們最多寫入capacity 個單位的數(shù)據(jù)到 Buffer 中, 例如一個 DoubleBuffer, 其 Capacity 是100, 那么我們最多可以寫入100個 double 數(shù)據(jù).

Position

當從一個 Buffer 中寫入數(shù)據(jù)時, 我們是從 Buffer 的一個確定的位置(position)開始寫入的. 在最初的狀態(tài)時, position 的值是0. 每當我們寫入了一個單位的數(shù)據(jù)后, position 就會遞增一.
當我們從 Buffer 中讀取數(shù)據(jù)時, 我們也是從某個特定的位置開始讀取的. 當我們調(diào)用了 filp()方法將 Buffer 從寫模式轉(zhuǎn)換到讀模式時, position 的值會自動被設(shè)置為0, 每當我們讀取一個單位的數(shù)據(jù), position 的值遞增1.
position 表示了讀寫操作的位置指針.

limit

limit - position 表示此時還可以寫入/讀取多少單位的數(shù)據(jù).
例如在寫模式, 如果此時 limit 是10, position 是2, 則表示已經(jīng)寫入了2個單位的數(shù)據(jù), 還可以寫入 10 - 2 = 8 個單位的數(shù)據(jù).

例子:
public class Test {
    public static void main(String args[]) {
        IntBuffer intBuffer = IntBuffer.allocate(10);
        intBuffer.put(10);
        intBuffer.put(101);
        System.err.println("Write mode: ");
        System.err.println("	Capacity: " + intBuffer.capacity());
        System.err.println("	Position: " + intBuffer.position());
        System.err.println("	Limit: " + intBuffer.limit());

        intBuffer.flip();
        System.err.println("Read mode: ");
        System.err.println("	Capacity: " + intBuffer.capacity());
        System.err.println("	Position: " + intBuffer.position());
        System.err.println("	Limit: " + intBuffer.limit());
    }
}

這里我們首先寫入兩個 int 值, 此時 capacity = 10, position = 2, limit = 10.
然后我們調(diào)用 flip 轉(zhuǎn)換為讀模式, 此時 capacity = 10, position = 0, limit = 2;

分配 Buffer

為了獲取一個 Buffer 對象, 我們首先需要分配內(nèi)存空間. 每個類型的 Buffer 都有一個 allocate()方法, 我們可以通過這個方法分配 Buffer:

ByteBuffer buf = ByteBuffer.allocate(48);

這里我們分配了48 * sizeof(Byte)字節(jié)的內(nèi)存空間.

CharBuffer buf = CharBuffer.allocate(1024);

這里我們分配了大小為1024個字符的 Buffer, 即 這個 Buffer 可以存儲1024 個 Char, 其大小為 1024 * 2 個字節(jié).

關(guān)于 Direct Buffer 和 Non-Direct Buffer 的區(qū)別

Direct Buffer:

所分配的內(nèi)存不在 JVM 堆上, 不受 GC 的管理.(但是 Direct Buffer 的 Java 對象是由 GC 管理的, 因此當發(fā)生 GC, 對象被回收時, Direct Buffer 也會被釋放)

因為 Direct Buffer 不在 JVM 堆上分配, 因此 Direct Buffer 對應(yīng)用程序的內(nèi)存占用的影響就不那么明顯(實際上還是占用了這么多內(nèi)存, 但是 JVM 不好統(tǒng)計到非 JVM 管理的內(nèi)存.)

申請和釋放 Direct Buffer 的開銷比較大. 因此正確的使用 Direct Buffer 的方式是在初始化時申請一個 Buffer, 然后不斷復(fù)用此 buffer, 在程序結(jié)束后才釋放此 buffer.

使用 Direct Buffer 時, 當進行一些底層的系統(tǒng) IO 操作時, 效率會比較高, 因為此時 JVM 不需要拷貝 buffer 中的內(nèi)存到中間臨時緩沖區(qū)中.

Non-Direct Buffer:

直接在 JVM 堆上進行內(nèi)存的分配, 本質(zhì)上是 byte[] 數(shù)組的封裝.

因為 Non-Direct Buffer 在 JVM 堆中, 因此當進行操作系統(tǒng)底層 IO 操作中時, 會將此 buffer 的內(nèi)存復(fù)制到中間臨時緩沖區(qū)中. 因此 Non-Direct Buffer 的效率就較低.

寫入數(shù)據(jù)到 Buffer
int bytesRead = inChannel.read(buf); //read into buffer.
buf.put(127);
從 Buffer 中讀取數(shù)據(jù)
//read from buffer into channel.
int bytesWritten = inChannel.write(buf);
byte aByte = buf.get();
重置 position

Buffer.rewind()方法可以重置 position 的值為0, 因此我們可以重新讀取/寫入 Buffer 了.
如果是讀模式, 則重置的是讀模式的 position, 如果是寫模式, 則重置的是寫模式的 position.
例如:

public class Test {
    public static void main(String[] args) {
        IntBuffer intBuffer = IntBuffer.allocate(2);
        intBuffer.put(1);
        intBuffer.put(2);
        System.err.println("position: " + intBuffer.position());

        intBuffer.rewind();
        System.err.println("position: " + intBuffer.position());
        intBuffer.put(1);
        intBuffer.put(2);
        System.err.println("position: " + intBuffer.position());

        
        intBuffer.flip();
        System.err.println("position: " + intBuffer.position());
        intBuffer.get();
        intBuffer.get();
        System.err.println("position: " + intBuffer.position());

        intBuffer.rewind();
        System.err.println("position: " + intBuffer.position());
    }
}

rewind() 主要針對于讀模式. 在讀模式時, 讀取到 limit 后, 可以調(diào)用 rewind() 方法, 將讀 position 置為0.

關(guān)于 mark()和 reset()

我們可以通過調(diào)用 Buffer.mark()將當前的 position 的值保存起來, 隨后可以通過調(diào)用 Buffer.reset()方法將 position 的值回復(fù)回來.
例如:

public class Test {
    public static void main(String[] args) {
        IntBuffer intBuffer = IntBuffer.allocate(2);
        intBuffer.put(1);
        intBuffer.put(2);
        intBuffer.flip();
        System.err.println(intBuffer.get());
        System.err.println("position: " + intBuffer.position());
        intBuffer.mark();
        System.err.println(intBuffer.get());

        System.err.println("position: " + intBuffer.position());
        intBuffer.reset();
        System.err.println("position: " + intBuffer.position());
        System.err.println(intBuffer.get());
    }
}

這里我們寫入兩個 int 值, 然后首先讀取了一個值. 此時讀 position 的值為1.
接著我們調(diào)用 mark() 方法將當前的 position 保存起來(在讀模式, 因此保存的是讀的 position), 然后再次讀取, 此時 position 就是2了.
接著使用 reset() 恢復(fù)原來的讀 position, 因此讀 position 就為1, 可以再次讀取數(shù)據(jù).

flip, rewind 和 clear 的區(qū)別 flip
flip 方法源碼
public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

Buffer 的讀/寫模式共用一個 position 和 limit 變量.
當從寫模式變?yōu)樽x模式時, 原先的 寫 position 就變成了讀模式的 limit.

rewind
rewind 方法源碼
public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
}

rewind, 即倒帶, 這個方法僅僅是將 position 置為0.

clear
clear 方法源碼:
public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}

根據(jù)源碼我們可以知道, clear 將 positin 設(shè)置為0, 將 limit 設(shè)置為 capacity.
clear 方法使用場景:

在一個已經(jīng)寫滿數(shù)據(jù)的 buffer 中, 調(diào)用 clear, 可以從頭讀取 buffer 的數(shù)據(jù).

為了將一個 buffer 填充滿數(shù)據(jù), 可以調(diào)用 clear, 然后一直寫入, 直到達到 limit.

例子:
IntBuffer intBuffer = IntBuffer.allocate(2);
intBuffer.flip();
System.err.println("position: " + intBuffer.position());
System.err.println("limit: " + intBuffer.limit());
System.err.println("capacity: " + intBuffer.capacity());

// 這里不能讀, 因為 limit == position == 0, 沒有數(shù)據(jù).
//System.err.println(intBuffer.get());

intBuffer.clear();
System.err.println("position: " + intBuffer.position());
System.err.println("limit: " + intBuffer.limit());
System.err.println("capacity: " + intBuffer.capacity());

// 這里可以讀取數(shù)據(jù)了, 因為 clear 后, limit == capacity == 2, position == 0,
// 即使我們沒有寫入任何的數(shù)據(jù)到 buffer 中.
System.err.println(intBuffer.get()); // 讀取到0
System.err.println(intBuffer.get()); // 讀取到0
Buffer 的比較

我們可以通過 equals() 或 compareTo() 方法比較兩個 Buffer, 當且僅當如下條件滿足時, 兩個 Buffer 是相等的:

兩個 Buffer 是相同類型的

兩個 Buffer 的剩余的數(shù)據(jù)個數(shù)是相同的

兩個 Buffer 的剩余的數(shù)據(jù)都是相同的.

通過上述條件我們可以發(fā)現(xiàn), 比較兩個 Buffer 時, 并不是 Buffer 中的每個元素都進行比較, 而是比較 Buffer 中剩余的元素.

本文由 yongshun 發(fā)表于個人博客, 采用署名-非商業(yè)性使用-相同方式共享 3.0 中國大陸許可協(xié)議.
非商業(yè)轉(zhuǎn)載請注明作者及出處. 商業(yè)轉(zhuǎn)載請聯(lián)系作者本人
Email: yongshun1228@gmail.com
本文標題為: Java NIO 的前生今世 之三 NIO Buffer 詳解
本文鏈接為: segmentfault.com/a/1190000006824155

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/65101.html

相關(guān)文章

  • 源碼之下無秘密 ── 做最好 Netty 源碼分析教程

    摘要:背景在工作中雖然我經(jīng)常使用到庫但是很多時候?qū)Φ囊恍└拍钸€是處于知其然不知其所以然的狀態(tài)因此就萌生了學習源碼的想法剛開始看源碼的時候自然是比較痛苦的主要原因有兩個第一網(wǎng)上沒有找到讓我滿意的詳盡的源碼分析的教程第二我也是第一次系統(tǒng)地學習這么大代 背景 在工作中, 雖然我經(jīng)常使用到 Netty 庫, 但是很多時候?qū)?Netty 的一些概念還是處于知其然, 不知其所以然的狀態(tài), 因此就萌生了學...

    shenhualong 評論0 收藏0
  • Netty 源碼分析之 一 揭開 Bootstrap 神秘紅蓋頭 (客戶端)

    摘要:目錄源碼分析之番外篇的前生今世的前生今世之一簡介的前生今世之二小結(jié)的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開神秘的紅蓋頭源碼分析之一揭開神秘的紅蓋頭客戶端源碼分析之一揭開神秘的紅蓋頭服務(wù)器 目錄 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NIO 的前生今世 之一 簡介 Java NIO 的前生今世 ...

    zhaot 評論0 收藏0
  • Java NIO 前生今世 之一 簡介

    摘要:簡介是由引進的異步由以下幾個核心部分組成和的對比和的區(qū)別主要體現(xiàn)在三個方面基于流而基于操作是阻塞的而操作是非阻塞的沒有概念而有概念基于與基于傳統(tǒng)的是面向字節(jié)流或字符流的而在中我們拋棄了傳統(tǒng)的流而是引入了和的概念在中我只能從中讀取數(shù)據(jù)到中或?qū)? 簡介 Java NIO 是由 Java 1.4 引進的異步 IO.Java NIO 由以下幾個核心部分組成: Channel Buffer Se...

    李義 評論0 收藏0
  • Java NIO 前生今世 之四 NIO Selector 詳解

    摘要:允許一個單一的線程來操作多個如果我們的應(yīng)用程序中使用了多個那么使用很方便的實現(xiàn)這樣的目的但是因為在一個線程中使用了多個因此也會造成了每個傳輸效率的降低使用的圖解如下為了使用我們首先需要將注冊到中隨后調(diào)用的方法這個方法會阻塞直到注冊在中的發(fā)送 Selector Selector 允許一個單一的線程來操作多個 Channel. 如果我們的應(yīng)用程序中使用了多個 Channel, 那么使用 S...

    lx1036 評論0 收藏0
  • Netty 源碼分析之 一 揭開 Bootstrap 神秘紅蓋頭 (服務(wù)器端)

    摘要:目錄源碼分析之番外篇的前生今世的前生今世之一簡介的前生今世之二小結(jié)的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開神秘的紅蓋頭源碼分析之一揭開神秘的紅蓋頭客戶端源碼分析之一揭開神秘的紅蓋頭服務(wù)器 目錄 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NIO 的前生今世 之一 簡介 Java NIO 的前生今世 ...

    張金寶 評論0 收藏0

發(fā)表評論

0條評論

madthumb

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<