真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

快速了解Java中NIO核心組件-創(chuàng)新互聯(lián)

背景知識

創(chuàng)新互聯(lián)公司主要從事成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)溫州,十年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792

同步、異步、阻塞、非阻塞

首先,這幾個概念非常容易搞混淆,但NIO中又有涉及,所以總結(jié)一下。

同步:API調(diào)用返回時調(diào)用者就知道操作的結(jié)果如何了(實際讀取/寫入了多少字節(jié))。

異步:相對于同步,API調(diào)用返回時調(diào)用者不知道操作的結(jié)果,后面才會回調(diào)通知結(jié)果。

阻塞:當無數(shù)據(jù)可讀,或者不能寫入所有數(shù)據(jù)時,掛起當前線程等待。

非阻塞:讀取時,可以讀多少數(shù)據(jù)就讀多少然后返回,寫入時,可以寫入多少數(shù)據(jù)就寫入多少然后返回。

對于I/O操作,根據(jù)Oracle官網(wǎng)的文檔,同步異步的劃分標準是“調(diào)用者是否需要等待I/O操作完成”,這個“等待I/O操作完成”的意思不是指一定要讀取到數(shù)據(jù)或者說寫入所有數(shù)據(jù),而是指真正進行I/O操作時,比如數(shù)據(jù)在TCP/IP協(xié)議棧緩沖區(qū)和JVM緩沖區(qū)之間傳輸?shù)倪@段時間,調(diào)用者是否要等待。

所以,我們常用的read()和write()方法都是同步I/O,同步I/O又分為阻塞和非阻塞兩種模式,如果是非阻塞模式,檢測到無數(shù)據(jù)可讀時,直接就返回了,并沒有真正執(zhí)行I/O操作。

總結(jié)就是,Java中實際上只有同步阻塞I/O、同步非阻塞I/O與異步I/O三種機制,我們下文所說的是前兩種,JDK1.7才開始引入異步I/O,那稱之為NIO.2。

傳統(tǒng)IO

我們知道,一個新技術(shù)的出現(xiàn)總是伴隨著改進和提升,JavaNIO的出現(xiàn)亦如此。

傳統(tǒng)I/O是阻塞式I/O,主要問題是系統(tǒng)資源的浪費。比如我們?yōu)榱俗x取一個TCP連接的數(shù)據(jù),調(diào)用InputStream的read()方法,這會使當前線程被掛起,直到有數(shù)據(jù)到達才被喚醒,那該線程在數(shù)據(jù)到達這段時間內(nèi),占用著內(nèi)存資源(存儲線程棧)卻無所作為,也就是俗話說的占著茅坑不拉屎,為了讀取其他連接的數(shù)據(jù),我們不得不啟動另外的線程。在并發(fā)連接數(shù)量不多的時候,這可能沒什么問題,然而當連接數(shù)量達到一定規(guī)模,內(nèi)存資源會被大量線程消耗殆盡。另一方面,線程切換需要更改處理器的狀態(tài),比如程序計數(shù)器、寄存器的值,因此非常頻繁的在大量線程之間切換,同樣是一種資源浪費。

隨著技術(shù)的發(fā)展,現(xiàn)代操作系統(tǒng)提供了新的I/O機制,可以避免這種資源浪費?;诖?,誕生了JavaNIO,NIO的代表性特征就是非阻塞I/O。緊接著我們發(fā)現(xiàn),簡單的使用非阻塞I/O并不能解決問題,因為在非阻塞模式下,read()方法在沒有讀取到數(shù)據(jù)時就會立即返回,不知道數(shù)據(jù)何時到達的我們,只能不停的調(diào)用read()方法進行重試,這顯然太浪費CPU資源了,從下文可以知道,Selector組件正是為解決此問題而生。

JavaNIO核心組件

1.Channel

概念

JavaNIO中的所有I/O操作都基于Channel對象,就像流操作都要基于Stream對象一樣,因此很有必要先了解Channel是什么。以下內(nèi)容摘自JDK1.8的文檔

Achannelrepresentsanopenconnectiontoanentitysuchasahardwaredevice,afile,anetworksocket,oraprogramcomponentthatiscapableofperformingoneormoredistinctI/Ooperations,forexamplereadingorwriting.

從上述內(nèi)容可知,一個Channel(通道)代表和某一實體的連接,這個實體可以是文件、網(wǎng)絡(luò)套接字等。也就是說,通道是JavaNIO提供的一座橋梁,用于我們的程序和操作系統(tǒng)底層I/O服務(wù)進行交互。

通道是一種很基本很抽象的描述,和不同的I/O服務(wù)交互,執(zhí)行不同的I/O操作,實現(xiàn)不一樣,因此具體的有FileChannel、SocketChannel等。

通道使用起來跟Stream比較像,可以讀取數(shù)據(jù)到Buffer中,也可以把Buffer中的數(shù)據(jù)寫入通道。

當然,也有區(qū)別,主要體現(xiàn)在如下兩點:

一個通道,既可以讀又可以寫,而一個Stream是單向的(所以分InputStream和OutputStream)

通道有非阻塞I/O模式

實現(xiàn)

JavaNIO中最常用的通道實現(xiàn)是如下幾個,可以看出跟傳統(tǒng)的I/O操作類是一一對應(yīng)的。

FileChannel:讀寫文件

DatagramChannel:UDP協(xié)議網(wǎng)絡(luò)通信

SocketChannel:TCP協(xié)議網(wǎng)絡(luò)通信

ServerSocketChannel:監(jiān)聽TCP連接

2.Buffer

NIO中所使用的緩沖區(qū)不是一個簡單的byte數(shù)組,而是封裝過的Buffer類,通過它提供的API,我們可以靈活的操縱數(shù)據(jù),下面細細道來。

與Java基本類型相對應(yīng),NIO提供了多種Buffer類型,如ByteBuffer、CharBuffer、IntBuffer等,區(qū)別就是讀寫緩沖區(qū)時的單位長度不一樣(以對應(yīng)類型的變量為單位進行讀寫)。

Buffer中有3個很重要的變量,它們是理解Buffer工作機制的關(guān)鍵,分別是

capacity(總?cè)萘浚?/p>

position(指針當前位置)

limit(讀/寫邊界位置)

Buffer的工作方式跟C語言里的字符數(shù)組非常的像,類比一下,capacity就是數(shù)組的總長度,position就是我們讀/寫字符的下標變量,limit就是結(jié)束符的位置。Buffer初始時3個變量的情況如下圖

在對Buffer進行讀/寫的過程中,position會往后移動,而limit就是position移動的邊界。由此不難想象,在對Buffer進行寫入操作時,limit應(yīng)當設(shè)置為capacity的大小,而對Buffer進行讀取操作時,limit應(yīng)當設(shè)置為數(shù)據(jù)的實際結(jié)束位置。(注意:將Buffer數(shù)據(jù)寫入通道是Buffer讀取操作,從通道讀取數(shù)據(jù)到Buffer是Buffer寫入操作)

在對Buffer進行讀/寫操作前,我們可以調(diào)用Buffer類提供的一些輔助方法來正確設(shè)置position和limit的值,主要有如下幾個

flip():設(shè)置limit為position的值,然后position置為0。對Buffer進行讀取操作前調(diào)用。

rewind():僅僅將position置0。一般是在重新讀取Buffer數(shù)據(jù)前調(diào)用,比如要讀取同一個Buffer的數(shù)據(jù)寫入多個通道時會用到。

clear():回到初始狀態(tài),即limit等于capacity,position置0。重新對Buffer進行寫入操作前調(diào)用。

compact():將未讀取完的數(shù)據(jù)(position與limit之間的數(shù)據(jù))移動到緩沖區(qū)開頭,并將position設(shè)置為這段數(shù)據(jù)末尾的下一個位置。其實就等價于重新向緩沖區(qū)中寫入了這么一段數(shù)據(jù)。

然后,看一個實例,使用FileChannel讀寫文本文件,通過這個例子驗證通道可讀可寫的特性以及Buffer的基本用法(注意FileChannel不能設(shè)置為非阻塞模式)。

FileChannel channel = new RandomAccessFile("test.txt", "rw").getChannel();
channel.position(channel.size());
// 移動文件指針到末尾(追加寫入)
ByteBuffer byteBuffer = ByteBuffer.allocate(20);
// 數(shù)據(jù)寫入Buffer
byteBuffer.put("你好,世界!\n".getBytes(StandardCharsets.UTF_8));
// Buffer -> Channel
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
	channel.write(byteBuffer);
}
channel.position(0);
// 移動文件指針到開頭(從頭讀?。?CharBuffer charBuffer = CharBuffer.allocate(10);
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
// 讀出所有數(shù)據(jù)
byteBuffer.clear();
while (channel.read(byteBuffer) != -1 || byteBuffer.position() > 0) {
	byteBuffer.flip();
	// 使用UTF-8解碼器解碼
	charBuffer.clear();
	decoder.decode(byteBuffer, charBuffer, false);
	System.out.print(charBuffer.flip().toString());
	byteBuffer.compact();
	// 數(shù)據(jù)可能有剩余
}
channel.close();

本文標題:快速了解Java中NIO核心組件-創(chuàng)新互聯(lián)
文章鏈接:http://weahome.cn/article/cocohs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部