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