在進(jìn)行數(shù)據(jù)傳輸?shù)臅r(shí)候,往往需要使用到緩沖區(qū),常用的緩沖區(qū)就是JDK NIO類(lèi)庫(kù)中提供的java.nio.Buffer,實(shí)現(xiàn)類(lèi)如下:
為長(zhǎng)島等地區(qū)用戶(hù)提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及長(zhǎng)島網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、長(zhǎng)島網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶(hù)提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶(hù)的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!在使用NIO編程時(shí),最常用的是其中的ByteBuffer,本篇分析ByteBuffer內(nèi)部的源碼實(shí)現(xiàn),順序從父類(lèi)Buffer入手,了解父類(lèi)中基礎(chǔ)API的實(shí)現(xiàn),再到各個(gè)實(shí)現(xiàn)子類(lèi)的實(shí)現(xiàn)。
Buffer
Buffer是存放一種特定的、原始的數(shù)據(jù)的容器。Buffer是一種特定原始類(lèi)型元素的線性的有限序列集合,其核心的屬性有capacity、limit、Position。
capacity:Buffer的容量,表示可以容納的元素?cái)?shù)量
limit:表示第一個(gè)不可以被讀取或者寫(xiě)入的元素的位置
position:表示下一個(gè)被讀取或者寫(xiě)入的位置
三者之間的關(guān)系如下:0<=position<=limit<=capacity
Buffer只有一個(gè)構(gòu)造方法:
這個(gè)構(gòu)造方式是protected的,也就是說(shuō)只有在包內(nèi)可以調(diào)用。構(gòu)造方法中除了capacity、limit、position外還有一個(gè)mark參數(shù),且校驗(yàn)了mark參數(shù)必須小于position。這個(gè)參數(shù)非常簡(jiǎn)單,用于標(biāo)記position的當(dāng)前位置,在進(jìn)行讀取寫(xiě)入之類(lèi)的操作之后可以通過(guò)API重新將position重置到標(biāo)記的位置,對(duì)應(yīng)的API為:Buffer#mark()\Buffer#reset()
Buffer中一個(gè)比較重要的API是Buffer#flip
這個(gè)方法就是將limit設(shè)置到position位置,將position調(diào)整到0,將mark設(shè)置為-1。
為什么需要有這么一個(gè)方法調(diào)整位置呢?
這個(gè)主要和Buffer只有一個(gè)position作為游標(biāo)相關(guān),讀寫(xiě)都是基于position的,所以在寫(xiě)操作完成之后需要進(jìn)行讀操作時(shí),需要將limit設(shè)置為position標(biāo)記有寫(xiě)到哪兒了,而將position 重新移到0,這樣就可以讀取到所有的寫(xiě)入數(shù)據(jù)。假設(shè)如果有兩個(gè)游標(biāo)分別表示讀取和寫(xiě)入的位置,是否就可以不用這個(gè)API了呢?
Buffer中的代碼都非常簡(jiǎn)單,主要就是自身屬性信息的設(shè)置和返回,像返回position、返回limit信息等,展開(kāi)細(xì)看。
ByteBuffer
ByteBuffer是Buffer的一個(gè)子類(lèi),是字節(jié)緩沖區(qū)。ByteBuffer在Buffer之上定義了6中操作:
通過(guò)當(dāng)前位置和指定位置的方式讀取和寫(xiě)入byte
通過(guò)get(byte[])的方式將ByteBuffer中的數(shù)據(jù)讀取到byte[]中
通過(guò)put(byte[])的方式將連續(xù)大量的byte數(shù)據(jù)寫(xiě)入緩沖區(qū)
通過(guò)當(dāng)前位置和指定位置的方式將其他類(lèi)型的數(shù)據(jù)寫(xiě)入緩沖區(qū)或從緩沖區(qū)讀取數(shù)據(jù)轉(zhuǎn)換成特定類(lèi)型
提供將ByteBuffer轉(zhuǎn)換成其他類(lèi)型的Buffer視圖的方法,例如ByteBuffer#asCharBuffer
提供compact、duplicate、slice來(lái)執(zhí)行一些對(duì)ByteBuffer的操作
ByteBuffer的構(gòu)造方法如下:
提供了兩個(gè)構(gòu)造方法,相對(duì)于Buffer增加了一個(gè)byte數(shù)組和一個(gè)offset。byte數(shù)組用于存儲(chǔ)數(shù)據(jù),offset表示ByteBuffer背后實(shí)際用于存儲(chǔ)的byte數(shù)據(jù)的其實(shí)位置。即你可以使用一個(gè)byte數(shù)據(jù),從它的任何一個(gè)下標(biāo)開(kāi)始存儲(chǔ)數(shù)據(jù),而不一定是0。
當(dāng)然,這兩個(gè)方法都是protected的,也就是說(shuō)實(shí)際我們“不能”通過(guò)這兩個(gè)方法去構(gòu)造我們需要的緩沖區(qū)。
那么當(dāng)我們需要使用緩沖區(qū)的時(shí)候我們?nèi)绾稳?gòu)造一個(gè)呢?ByteBuffer提供了兩個(gè)API:ByteBuffer#allocateDirect、ByteBuffer#allocate
ByteBuffer#allocateDirect分配一個(gè)DirectByteBuffer,即這個(gè)緩沖區(qū)是使用堆外內(nèi)存的。
ByteBuffer#allocate在JVM堆上分配一塊內(nèi)存。
新分配的內(nèi)存position都是0,limit為容量,初始內(nèi)部填充的數(shù)據(jù)都為0。
除了通過(guò)allocate去創(chuàng)建ByteBuffer,還有一種方式是通過(guò)wrap來(lái)包裝一個(gè)byte數(shù)組,這樣就可以使用ByteBuffer的API來(lái)對(duì)byte數(shù)據(jù)進(jìn)行操作。
因?yàn)閎yte數(shù)據(jù)本身在堆內(nèi),所以wrap的ByteBuffer也就是HeapByteBuffer。
offset和length將被作為ByteBuffer初始的position和limit。
allocate和wrap都是創(chuàng)建了“新”的ByteBuffer,這里新的含義是他們背后都有自己獨(dú)立的byte數(shù)組用于存儲(chǔ)數(shù)據(jù)。還有一類(lèi)API,他們也創(chuàng)建ByteBuffer,但是它只是個(gè)視圖,擁有自己的position、limit等屬性,但是存儲(chǔ)的byte數(shù)組是共享的:
ByteBuffer#slice:創(chuàng)建一個(gè)的ByteBuffer,內(nèi)容是當(dāng)前ByteBuffer的一個(gè)子序列,共享一個(gè)byte數(shù)組;兩個(gè)ByteBuffer的position、limit、mark是獨(dú)立的;新ByteBuffer的起始位置是原ByteBuffer的position位置
ByteBuffer#duplicate:“復(fù)制”一個(gè)ByteBuffer,共享存儲(chǔ)的byte數(shù)據(jù),擁有獨(dú)立的capacity、limit、position、mark屬性;如果當(dāng)前ByteBuffer是DirectByteBuffer,那么新Buffer也是DirectByteBuffer,如果當(dāng)前是HeapByteBuffer,那么新分配的也是HeapByteBuffer
ByteBuffer提供另外一類(lèi)API來(lái)將自己轉(zhuǎn)換成另一個(gè)類(lèi)型的緩沖區(qū):
ByteBuffer#asXXXBuffer:比如asLongBuffer創(chuàng)建一個(gè)新的LongBuffer,底層的存儲(chǔ)還是共享當(dāng)前的byte數(shù)組,同時(shí)擁有自己的position、limit、mark屬性,新Buffer的position為0,limit和capacity為原Buffer除8,因?yàn)橐粋€(gè)long類(lèi)型占用8個(gè)byte;其他asXXXBuffer方法都類(lèi)似
ByteBuffer中還有一類(lèi)API是提供基于當(dāng)前位置或者指定位置來(lái)讀寫(xiě)數(shù)據(jù)的:
byte getByte()
byte getByte(int index)
int getInt()
int getInt(int index)
...
這兩種API的差異是沒(méi)有參數(shù)的API會(huì)從當(dāng)前position開(kāi)始讀取數(shù)據(jù),之后會(huì)修改position位置。而通過(guò)傳入index,會(huì)從index開(kāi)始讀取數(shù)據(jù),不會(huì)變更position信息。所以如果只是要讀取數(shù)據(jù),并不希望更改Buffer本身的信息(position),應(yīng)該使用帶有參數(shù)的方法。
ByteBuffer的內(nèi)容只有這么多,接著看它的子類(lèi)實(shí)現(xiàn),主要是HeapByteBuffer和DirectByteBuffer。
HeapByteBuffer
HeapByteBuffer顧名思義就是JVM堆上的字節(jié)緩沖區(qū),他用于緩存數(shù)據(jù)的byte數(shù)組就是直接在堆內(nèi)申請(qǐng)的。默認(rèn)的構(gòu)造方法直接就是new一個(gè)byte數(shù)組作為數(shù)據(jù)存儲(chǔ)的緩沖區(qū)。
HeapByteBuffer非常簡(jiǎn)單,就是實(shí)現(xiàn)了ByteBuffer定義的各種put和get方法,沒(méi)有什么好分析的。
DirectByteBuffer
DirectByteBuffer翻譯過(guò)來(lái)就是直接的字節(jié)緩沖區(qū),它是使用直接內(nèi)存的,即不從JVM的堆上分配內(nèi)存。
首先看DirectByteBuffer的一個(gè)內(nèi)部類(lèi):Deallocator。從類(lèi)名可以看出這個(gè)類(lèi)應(yīng)該是做“回收的”。
從代碼看,Deallocator實(shí)現(xiàn)了Runnable接口,run方法內(nèi)的實(shí)現(xiàn)就是通過(guò)unsafe釋放內(nèi)存。
結(jié)合Cleaner就能明白Cleaner是統(tǒng)一的接口,返回Cleaner來(lái)執(zhí)行清楚操作,而真正的內(nèi)存回收在Deallocator中執(zhí)行。
接著看DirectByteBuffer的構(gòu)造方法:
只有一個(gè)容量作為參數(shù),而內(nèi)存是直接通過(guò)unsafe分配的,可見(jiàn)內(nèi)存是直接分配的,而不是在堆上申請(qǐng)的。另外這是一個(gè)受保護(hù)的方法,也就是說(shuō)用戶(hù)是不能直接調(diào)用的。
另外還有幾個(gè)構(gòu)造方法,可以直接通過(guò)內(nèi)存地址來(lái)初始化,或者通過(guò)文件描述符來(lái)初始化(For memory-mapped buffers),通過(guò)已近存在的DirectBuffer來(lái)初始化。
這些方法都是提供給MMAP之類(lèi)的使用的,一般用戶(hù)都不會(huì)直接調(diào)用到。
剩下的方法,像是slice、duplicate,包括通過(guò)address返回內(nèi)存地址都非常簡(jiǎn)單就不描述了。
另外DirectByteBuffer內(nèi)部還有一個(gè)特殊的方法是asReadOnlyBuffer方法,返回了一個(gè)DirectByteBufferR對(duì)象。下面看一下DirectByteBufferR做了些什么。
簡(jiǎn)單從方法出發(fā),大概就是返回只讀的一個(gè)對(duì)象,不能做寫(xiě)入操作。
實(shí)際上也是非常簡(jiǎn)單,所有的put操作都拋出了異常。剩下get和slice等也類(lèi)似,不再贅述。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。