Buffer
BIO的局限性
Server端應(yīng)該使用盡肯能少的線程來處理多個client請求。BIO下,每個client都要創(chuàng)建一個對應(yīng)的線程來處理,線程數(shù)量越多,上限文切換造成的資源損耗越大。在BIO中使用線程池,就意味著線程池中的維護(hù)的線程數(shù)就是server端支持最多有多少個client來連接。
NIO Buffer
一個Buffer對象是固定數(shù)量的數(shù)據(jù)的容器。其作用是一個存儲器或分段運(yùn)輸區(qū),在這里數(shù)據(jù)可以被存儲并在之后用于檢索。對于每個非布爾原始數(shù)據(jù)類型都有一個緩沖區(qū)類。盡管緩沖區(qū)作用于他們存儲的原始數(shù)據(jù)類型,但緩沖區(qū)十分傾向于處理字節(jié)。緩沖區(qū)的工作與通道緊密聯(lián)系。通道是I/O傳輸發(fā)生是通過的入口,而緩沖區(qū)是這些數(shù)據(jù)傳輸?shù)膩碓椿蚰繕?biāo)。對于離開緩沖區(qū)的傳輸,是將緩沖區(qū)的數(shù)據(jù)傳送到通道。對于傳回緩沖區(qū)的傳輸,是將通道的數(shù)據(jù)放置在緩沖區(qū)中。這種在協(xié)同對象之間進(jìn)行的緩沖區(qū)數(shù)據(jù)傳遞是高校數(shù)據(jù)處理的關(guān)鍵。
Buffer定義所有緩沖區(qū)類型共有的曹鄒,無論是它們所包含的數(shù)據(jù)類型還是可能具有的特定行為。
緩沖區(qū)是包在一個對象內(nèi)的基本數(shù)據(jù)元素數(shù)組。Buffer類的優(yōu)點(diǎn)是他將關(guān)于數(shù)據(jù)的數(shù)據(jù)內(nèi)容和信息包含在一個單一的對象中。Buffer類以及它專有的子類定義了一個用于處理數(shù)據(jù)緩沖的API。
public abstract class Buffer{
// mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0';
private int limit;
private int capacity;
public final int capacity();
public final int position();
public final Buffer position(int newPosition);
public final int limit();
public final Buffer limit(int newLimit);
public final Buffer mark();
public final Buffer reset();
public final Buffer clear();
public final Buffer flip();
public final Buffer rewind();
public final int remaining();
public final boolean hasRemaining();
public abstract boolean isReadOnly();
public abstract boolean hasArray();
public abstract Object array();
public abstract int arrayOffset();
public abstract boolean isDirect();
}
容量(Capacity):緩沖區(qū)能夠容納的數(shù)據(jù)元素的最大數(shù)量,可以理解為數(shù)組的長度。在緩沖區(qū)創(chuàng)建時被設(shè)定,并且永不能改變
上界(Limit):緩沖區(qū)的第一個不能被讀或?qū)懙脑氐乃饕??;蛘f緩沖區(qū)中現(xiàn)存元素的技數(shù)
位置(Position):下一個要被讀寫的元素的索引。Buffer類提供了get()和put()函數(shù)來讀取或存入數(shù)據(jù),position位置會自動進(jìn)行相應(yīng)的更新
標(biāo)記(Mark):一個備忘位置。調(diào)用mark()來設(shè)定mark = position。調(diào)用reset()設(shè)定position = mark。標(biāo)記在設(shè)定前是未定義的。
public abstract class ByteBuffer{
public static ByteBuffer allocateDirect(int capacity);
public static ByteBuffer allocate(int capacity);
public static ByteBuffer wrap(byte[] array);
public static ByteBuffer wrap(byte[] array, int offset, int length);
public abstract byte get();
public abstract byte get(int index);
public abstract ByteBuffer put(byte b);
public abstract ByteBuffer put(int index, int b);
}
新的緩沖區(qū)是由分配(allocate)或包裝(wrap)操作創(chuàng)建的。allocate操作創(chuàng)建一個緩沖區(qū)對象并分配一個私有的空間來儲存容量大小的數(shù)據(jù)元素。wrap操作創(chuàng)建一個緩沖區(qū)對象但是不分配任何空間來儲存數(shù)據(jù)元素。它使用你所提供的的數(shù)組作為存儲空間來儲存穿沖去中的數(shù)據(jù)元素。
存儲操作時通過get和put操作進(jìn)行的,get和put可以使相對的或是絕對的。相對方案是不帶有索引參數(shù)的函數(shù)。當(dāng)相對函數(shù)被調(diào)用時,位置在返回時前進(jìn)一。若位置前進(jìn)過多,相對運(yùn)算就會拋出異常。絕對存取不會影響緩沖區(qū)的位置屬性,但若提供的索引超出范圍,也將拋出IndexOutOfBoundsException異常。
flip()函數(shù)可以將position值重新設(shè)為0,同時將limit設(shè)置為當(dāng)當(dāng)前緩沖區(qū)內(nèi)的最后一個元素的索引。rewind()將position設(shè)置為0單不會改變limit的值。
clear()函數(shù)可以讓緩沖區(qū)恢復(fù)到初始狀態(tài),但并不改變緩沖區(qū)中的任何數(shù)據(jù)元素。即position=0, limit=capacity,mark=-1。
mark()方法能使緩沖區(qū)記住一個position并在之后將其返回。緩沖區(qū)的標(biāo)記在mark()行數(shù)被調(diào)用之前是未定義的,值為-1,調(diào)用時mark被設(shè)為當(dāng)前的position的值。reset()函數(shù)將position設(shè)為當(dāng)前的mark值。若mark未定義,調(diào)用reset()將導(dǎo)致InvalidMarkException異常。
compact()方法會將未讀數(shù)據(jù)元素需要下移以使第一個元素索引為0。
復(fù)制緩沖區(qū)
緩沖區(qū)的復(fù)制有兩種:
完全復(fù)制:調(diào)用duplicate()或asReadOnluBuffer()函數(shù)
部分復(fù)制:調(diào)用slice()
duolicate()函數(shù)創(chuàng)建了一個與原始緩沖區(qū)相似的新緩沖區(qū)。兩個緩沖區(qū)共享數(shù)據(jù)元素,擁有同樣的容量,但每個緩沖區(qū)擁有各自的位置,上界和標(biāo)記屬性。對一個緩沖區(qū)的數(shù)據(jù)元素所做的改變會反映在另一個緩沖區(qū)上。若原始的緩沖區(qū)為只讀或直接緩沖區(qū),那新的緩沖區(qū)將繼承這些屬性。
CharBuffer buffer = CharBuffer.allocate(8); buffer.position(3).limit(6).mark().position(5); CharBuffer dupBuffer = buffer.duplicate(); buffer.clear();
asReadOnlyBuffer()函數(shù)來生成一個只讀的緩沖區(qū)視圖。這個新的緩沖區(qū)不允許使用put(),并且isReadOnly()會返回true。對這一只讀緩沖區(qū)調(diào)用put()函數(shù)會導(dǎo)致ReadOnlyBufferException異常
直接緩沖區(qū)
直接字節(jié)緩沖區(qū)通常是I/O操作最好的選擇。在設(shè)計(jì)方面,它們支持JVM可用的最高效I/O機(jī)制。非直接字節(jié)緩沖區(qū)可以被傳遞給通道,但這樣可能會導(dǎo)致性能損耗。通常非直接緩沖不可能成為一個本地I/O操作的目標(biāo)。若向一個通道中傳遞一個非直接ByteBuffer對象用于寫入,通道可能會在每次調(diào)用中隱含地進(jìn)行下面的操作:
1. 創(chuàng)建一個臨時的直接ByteBuffer對象
2. 將非直接緩沖區(qū)的內(nèi)容復(fù)制到臨時緩沖區(qū)中
3. 使用臨時緩沖區(qū)執(zhí)行低層次I/O操作
4. 臨時緩沖區(qū)對象離開作用域,并最終成為被回收的無用數(shù)據(jù)
直接緩沖區(qū)是I/O的最佳選擇,但可能比創(chuàng)建非直接緩沖區(qū)要花費(fèi)更高的成本。直接緩沖區(qū)使用的內(nèi)存是通過調(diào)用給本地操作系統(tǒng)方面的代碼分配的,繞過了JVM堆棧。建立和銷毀直接緩沖區(qū)會明顯比具有堆棧的緩沖區(qū)更加破費(fèi),具體取決于操作系統(tǒng)和JVM的實(shí)現(xiàn)。直接緩沖區(qū)的內(nèi)存區(qū)域不受無用存儲單元收集支配。
直接ByteBuffer是通過調(diào)用具有所需容量的ByteBuffer.allocateDirect()函數(shù)產(chǎn)生的。通常用wrap()函數(shù)所創(chuàng)建的被包裝的緩沖區(qū)總是非直接的。通過緩沖區(qū)的isDirect()方法來判斷是否是直接緩沖區(qū)。
讀取數(shù)據(jù)總是需要通過內(nèi)核空間傳遞到用戶空間,而往外寫數(shù)據(jù)總是要通過用戶空間到內(nèi)核空間。JVM堆棧屬于用戶空間。直接緩沖區(qū)就是內(nèi)核空間。內(nèi)核空間的存在java中是通過Unsafe這個類來調(diào)用的。
內(nèi)存映射緩沖區(qū)
映射緩沖區(qū)是帶有存儲的文件,通過內(nèi)存映射來存取數(shù)據(jù)元素的字節(jié)緩沖區(qū)。映射緩沖區(qū)通常是直接存取內(nèi)存的,只能通過FileChannel類來創(chuàng)建。映射緩沖區(qū)的用法和直接緩沖區(qū)類似,但MappedByteBuffer對象可以獨(dú)立于文件存取形式的許多特定字符。
MappedByteBuffer在大文件處理方面性能比較好。
總結(jié)
- 上一篇: 安全工具(免费杀毒软件Avast、免费防
- 下一篇: Collection