張健立(集寧師范學(xué)院 計(jì)算機(jī)系,內(nèi)蒙古 烏蘭察布 012000)
?
NIO高性能技術(shù)在Java網(wǎng)絡(luò)通信中的應(yīng)用研究
張健立
(集寧師范學(xué)院計(jì)算機(jī)系,內(nèi)蒙古烏蘭察布012000)
摘要:Java平臺(tái)提供了比較豐富的標(biāo)準(zhǔn)類I/O庫來滿足一般應(yīng)用場(chǎng)景下的通信需求,但對(duì)于大量的并發(fā)通信請(qǐng)求,就必須使用一定的技術(shù)手段來解決系統(tǒng)面臨的通信瓶頸。到了JDK 1.4中Java提供了新的I/O(NIO)類庫,到了Java7中NIO的補(bǔ)充類庫越發(fā)強(qiáng)大,很多原來需要開發(fā)人員編寫的功能,在現(xiàn)在的類庫中都有了實(shí)現(xiàn)。
關(guān)鍵詞:NIO;通道;阻塞;異步通訊
JAVA是目前比較流行的程序開發(fā)語言,在現(xiàn)實(shí)中大量的網(wǎng)絡(luò)應(yīng)用也采用了Java語言來開發(fā)。程序中與I/O相關(guān)的計(jì)算所花費(fèi)的時(shí)間占較大比重,這其中的主要原因是在進(jìn)行I/O通信時(shí),一般需要競(jìng)爭操作系統(tǒng)的有限資源,或是需要等待速度較慢的外部設(shè)備完成其操作,從而使I/O相關(guān)的計(jì)算所等待的時(shí)間較長。為了優(yōu)化系統(tǒng)性能,提升I/O相關(guān)操作的性能對(duì)應(yīng)用程序的整體運(yùn)行性能有比較大的幫助。Java平臺(tái)提供了比較豐富的標(biāo)準(zhǔn)類I/O庫來滿足一般應(yīng)用場(chǎng)景下的通信需求,但對(duì)于大量的并發(fā)通信請(qǐng)求,就必須使用一定的技術(shù)手段來解決系統(tǒng)面臨的通信瓶頸。到了JDK 1.4中Java提供了新的I/O(NIO)類庫,到了Java7中NIO的補(bǔ)充類庫越發(fā)強(qiáng)大,很多原來需要開發(fā)人員編寫的功能,在現(xiàn)在的類庫中都有了實(shí)現(xiàn)。
如果要實(shí)現(xiàn)一個(gè)網(wǎng)絡(luò)客戶端程序,需要?jiǎng)?chuàng)建一個(gè)java.net.Socket類的對(duì)象,再連接到遠(yuǎn)程服務(wù)器。服務(wù)器端需要?jiǎng)?chuàng)建一個(gè)java.net. ServerSocket類的對(duì)象并使用其accept方法在指定端口進(jìn)行監(jiān)聽,調(diào)用accept時(shí)會(huì)處于阻塞狀態(tài),等待客戶端程序的連接請(qǐng)求。這給網(wǎng)絡(luò)編程帶來了一個(gè)很大的問題,我們假設(shè)對(duì)上述的服務(wù)器/客戶機(jī)模型,提出更高的要求,即讓服務(wù)器同時(shí)為多個(gè)客戶機(jī)提供一問一答的服務(wù),就需要在服務(wù)器端使用多線程。多線程的目的是讓每個(gè)連接都擁有獨(dú)立的線程,主線程持續(xù)等待客戶端的連接請(qǐng)求,如果有連接,則創(chuàng)建新線程,并在新線程中提供為前例同樣的問答服務(wù),這樣任何一個(gè)連接的阻塞都不會(huì)影響其他的連接。但是這種連接方式要求有一個(gè)客戶請(qǐng)求,服務(wù)器就要為之開啟一個(gè)線程,因?yàn)槊縿?chuàng)建一個(gè)線程都要消耗系統(tǒng)資源,顯然服務(wù)器的負(fù)載壓力比較大。
如果程序?qū)W(wǎng)絡(luò)操作的并發(fā)性和吞吐量的要求比較高,那么阻塞式的套接字通道就不能比較簡單地滿足程序的要求,這時(shí)比較好的辦法是通過非阻塞式的套接字通道實(shí)現(xiàn)多路復(fù)用或使用NIO.2中的異步套接字通道。
多路復(fù)用的思想是,通過一個(gè)專門的選擇器(selector)來同時(shí)對(duì)多個(gè)套接字通道進(jìn)行監(jiān)聽。當(dāng)其中的某些套接字通道上有它感興趣的事件發(fā)生時(shí),這些通道會(huì)變?yōu)榭捎玫臓顟B(tài),可以在選擇器的選擇操作中被選中,選擇器通過一次選中操作可以獲取這些被選中的通道列表,然后根據(jù)發(fā)生的事件類型分別進(jìn)行處理。
多路復(fù)用的實(shí)現(xiàn)方式的核心是選擇器,即java.nio.channels.Selector類的對(duì)象,非阻塞式的套接字通道可以通過register方法注冊(cè)到某個(gè)Selector類的對(duì)象上,以聲明由該Selector類的對(duì)象來管理當(dāng)前這個(gè)套接字通道。在進(jìn)行注冊(cè)時(shí),需要提供一個(gè)套接字通道感興趣的事件列表,這些事件包括連接完成、接收到新連接請(qǐng)求、有數(shù)據(jù)可讀和可以寫入數(shù)據(jù)等。這些事件定義在java.nio.channels.SelectionKey類中,在完成注冊(cè)之后,可以調(diào)用Selector類對(duì)象的select方法來進(jìn)行選擇。這里需要注意的地方是一個(gè)套接字通道只有在通過confgureBlocking方法設(shè)置為非阻塞模式之后,才能被注冊(cè)到選擇器上。
在Java7中NIO.2引入了新的異步通道的概念,并提供了異步文件通道和異步套接字通道的實(shí)現(xiàn)。對(duì)于文件通道來說,一般的操作如讀和寫,都是同步進(jìn)行的,調(diào)用者會(huì)處于阻塞狀態(tài),以等待相應(yīng)操作的完成。而對(duì)于異步套接字通道來說,阻塞式套接字通道的使用方式與文件通道相同,而非阻塞式套接字通道的使用方式則依靠選擇器來完成。異步通道一般提供兩種使用方式:一種是通過Java同步工具包中的java.util.concurrent. Future類的對(duì)象來表示異步操作的結(jié)果;另外一種是在執(zhí)行操作時(shí)傳入一個(gè)java.nio.channels.CompletionHandler接口的實(shí)現(xiàn)對(duì)象作為操作完成時(shí)的回調(diào)方法。這兩種使用方式的區(qū)別只在于調(diào)用者通過何種方式來使用異步操作的結(jié)果。在使用Future類的對(duì)象時(shí),要求調(diào)用者在合適的時(shí)機(jī)顯式的通過Future類的對(duì)象的get方法來得到實(shí)際的操作結(jié)果;而在使用CompletionHandler接口時(shí),實(shí)際調(diào)用的結(jié)果作為回調(diào)方法的參數(shù)來給出。
I/O操作一直是程序開發(fā)中的重要組成部分,高效的I/O操作實(shí)現(xiàn)也是很多程序開發(fā)人員一直所追求的目標(biāo)。不同的傳輸實(shí)體本身的特征會(huì)使在其上進(jìn)行的I/O操作有各自不同的特點(diǎn),I/O操作也需要根據(jù)這些實(shí)體的特征來做出相應(yīng)的調(diào)整。如果程序是基于Java7創(chuàng)建的,從通道開始入手是一個(gè)很不錯(cuò)的選擇,但是對(duì)于流的操作則盡量少使用通道。
參考文獻(xiàn):
[1]蔡天鳴,王若愚.Java SE7平臺(tái)下的NIO.2探析[J].軟件導(dǎo)刊,2011(08).
[2]成富.深入理解Java7核心技術(shù)與最佳實(shí)踐[J].機(jī)械工業(yè)出版社,2012(05).
[3]王潔.JAVA NIO在Socket通訊中的應(yīng)用[J].成都信息工程學(xué)院學(xué)報(bào),2003(09).
本文系項(xiàng)目基金階段性課題:“基于Java NIO高性能網(wǎng)絡(luò)應(yīng)用技術(shù)的研究”:集寧師范學(xué)院科學(xué)研究項(xiàng)目 (項(xiàng)目編號(hào):jsky2016044)
DOI:10.16640/j.cnki.37-1222/t.2016.11.147