Java NIO詳解

NIO含義

New I/O,原因在于它相對(duì)于之前的I/O類(lèi)庫(kù)是新增的躲查。
由于之前老的I/O類(lèi)庫(kù)是阻塞I/O酌心,New I/O類(lèi)庫(kù)的目標(biāo)就是要讓Java支持非阻塞I/O弟蚀,所以蚤霞,更多的人喜歡稱之為非阻塞I/O(Non-block I/O)。

SocketChannel和ServerSocketChannel

與Socket類(lèi)和ServerSocket類(lèi)相對(duì)應(yīng)义钉,NIO也提供了SocketChannel和ServerSocketChannel兩種不同的套接字通道實(shí)現(xiàn)昧绣。這兩種新增的通道都支持阻塞和非阻塞兩種模式。
低負(fù)載捶闸、低并發(fā)的應(yīng)用程序可以選擇同步阻塞I/O以降低編程復(fù)雜度夜畴;對(duì)于高負(fù)載、高并發(fā)的網(wǎng)絡(luò)應(yīng)用删壮,需要使用NIO的非阻塞模式進(jìn)行開(kāi)發(fā)贪绘。

NIO類(lèi)庫(kù)簡(jiǎn)介

NIO彌補(bǔ)了原來(lái)同步阻塞I/O的不足,它在標(biāo)準(zhǔn)Java代碼中提供了高速的央碟、面向塊的I/O税灌。

通過(guò)定義包含數(shù)據(jù)的類(lèi),以及通過(guò)以塊的形式處理這些數(shù)據(jù)亿虽,NIO不用使用本機(jī)代碼就可以利用低級(jí)優(yōu)化菱涤,這是原來(lái)的I/O包所無(wú)法做到的。

NIO類(lèi)庫(kù)簡(jiǎn)介 緩沖區(qū)Buffer

Buffer是一個(gè)對(duì)象经柴,它包含一些要寫(xiě)入或者要讀出的數(shù)據(jù)狸窘。
在NIO類(lèi)庫(kù)中加入Buffer對(duì)象,體現(xiàn)了新庫(kù)與原I/O的一個(gè)重要區(qū)別坯认。
在面向流的I/O中,可以將數(shù)據(jù)直接寫(xiě)入或者將數(shù)據(jù)直接讀到Stream對(duì)象中。
在NIO庫(kù)中牛哺,所有數(shù)據(jù)都是用緩沖區(qū)處理的陋气。在讀取數(shù)據(jù)時(shí),它是直接讀到緩沖區(qū)中的引润;在寫(xiě)入數(shù)據(jù)時(shí)巩趁,寫(xiě)入到緩沖區(qū)中。任何時(shí)候訪問(wèn)NIO中的數(shù)據(jù)淳附,都是通過(guò)緩沖區(qū)進(jìn)行操作议慰。
緩沖區(qū)實(shí)質(zhì)上是一個(gè)數(shù)組。
緩沖區(qū)不僅僅是一個(gè)數(shù)組奴曙,緩沖區(qū)提供了對(duì)數(shù)據(jù)的結(jié)構(gòu)化訪問(wèn)以及維護(hù)讀寫(xiě)位置(limit)等信息别凹。
一個(gè)ByteBuffer提供了一組功能用于操作byte數(shù)組。
每一種Java基本類(lèi)型(除了Boolean類(lèi)型)都對(duì)應(yīng)有一種緩沖區(qū):
ByteBuffer:字節(jié)緩沖區(qū)
CharBuffer:字符緩沖區(qū)
ShortBuffer:短整型緩沖區(qū)
IntBuffer:整形緩沖區(qū)
LongBuffer:長(zhǎng)整形緩沖區(qū)
FloatBuffer:浮點(diǎn)型緩沖區(qū)
DoubleBuffer:雙精度浮點(diǎn)型緩沖區(qū)

每一個(gè)Buffer類(lèi)都是Buffer接口的一個(gè)子實(shí)例洽糟。除了ByteBuffer炉菲,每一個(gè)Buffer類(lèi)都有完全一樣的操作,只是它們所處理的數(shù)據(jù)類(lèi)型不一樣坤溃。
因?yàn)榇蠖鄶?shù)標(biāo)準(zhǔn)I/O操作都使用ByteBuffer拍霜,所以它在具有一般緩沖區(qū)的操作之外還提供了一些特有的操作,以方便網(wǎng)絡(luò)讀寫(xiě)薪介。

NIO類(lèi)庫(kù)簡(jiǎn)介 通道Channel

Channel是一個(gè)通道祠饺,網(wǎng)絡(luò)數(shù)據(jù)通過(guò)Channel讀取和寫(xiě)入。
通道與流的不同之處在于通道是雙向的汁政,流只是在一個(gè)方向上移動(dòng)(一個(gè)流必須是InputStream或者OutputStream的子類(lèi))道偷,而通道可以用于讀、寫(xiě)或者二者同時(shí)進(jìn)行烂完。
因?yàn)镃hannel是全雙工的试疙,所以它可以比流更好地映射底層操作系統(tǒng)的API。特別是在UNIX網(wǎng)絡(luò)編程模型中抠蚣,底層操作系統(tǒng)的通道都是全雙工的祝旷,同時(shí)支持讀寫(xiě)操作。

自頂向下看嘶窄,前三層主要是Channel接口怀跛,用于定義它的功能,后面是一些具體的功能類(lèi)(抽象類(lèi))柄冲。從類(lèi)圖可以看出吻谋,實(shí)際上Channel可以分為兩大類(lèi):用于網(wǎng)絡(luò)讀寫(xiě)的SelectableChannel和用于文件操作的FileChannel。
ServerSocketChannel和SocketChannel都是SelectableChannel的子類(lèi)

多路復(fù)用器Selector

多路復(fù)用器Selector是Java NIO編程的基礎(chǔ)
多路復(fù)用器提供選擇已經(jīng)就緒的任務(wù)的能力现横。
Selector會(huì)不斷地輪詢注冊(cè)在其上的Channel漓拾,如果某個(gè)Channel上面發(fā)生讀或者寫(xiě)事件阁最,這個(gè)Channnel就處于就緒狀態(tài),會(huì)被Selector輪詢出來(lái)骇两,然后通過(guò)SelectionKey可以獲取就緒Channel的集合速种,進(jìn)行后續(xù)的I/O操作。
一個(gè)多路復(fù)用器Selector可以同時(shí)輪詢多個(gè)Channel低千,由于JDK使用了epoll()代替?zhèn)鹘y(tǒng)的select實(shí)現(xiàn)配阵,所以它并沒(méi)有最大連接句柄1024/2048的限制。這也就意味著只需要一個(gè)線程負(fù)責(zé)Selector的輪詢示血,就可以接入成千上萬(wàn)的客戶端棋傍,這確實(shí)是個(gè)非常巨大的進(jìn)步。

下面用代碼簡(jiǎn)單描述這個(gè)過(guò)程:


使用NIO技術(shù)編寫(xiě)TimeServer

使用NIO技術(shù)編寫(xiě)TimeClient原理講解

時(shí)序圖:



用代碼講解一下過(guò)程:

使用NIO技術(shù)編寫(xiě)TimeClient

注意

下面這種關(guān)閉socket的方法是錯(cuò)誤的


如果服務(wù)端沒(méi)有對(duì)這種情況進(jìn)行處理會(huì)出現(xiàn)一下的錯(cuò)誤:


服務(wù)端最好是在讀取數(shù)據(jù)的時(shí)候做一下處理:

優(yōu)勢(shì)

NIO編程的難度比同步阻塞BIO大很多难审。
請(qǐng)注意以上的代碼中并沒(méi)有考慮“半包讀”和“半包寫(xiě)”瘫拣,如果加上這些,代碼將會(huì)更加復(fù)雜剔宪。拂铡。
(1)客戶端發(fā)起的連接操作是異步的,可以通過(guò)在多路復(fù)用器注冊(cè)O(shè)P_CONNECT等待后續(xù)結(jié)果葱绒,不需要像之前的客戶端那樣被同步阻塞感帅。
(2)SocketChannel的讀寫(xiě)操作都是異步的,如果沒(méi)有可讀寫(xiě)的數(shù)據(jù)它不會(huì)同步等待地淀,直接返回失球,這樣I/O通信線程就可以處理其他的鏈路,不需要同步等待這個(gè)鏈路可用帮毁。
(3)線程模型的優(yōu)化:由于JDK的Selector在Linux等主流操作系統(tǒng)上通過(guò)epoll實(shí)現(xiàn)实苞,它沒(méi)有連接句柄數(shù)的限制(只受限于操作系統(tǒng)的最大句柄數(shù)或者對(duì)單個(gè)進(jìn)程的句柄限制),這意味著一個(gè)Selector線程可以同時(shí)處理成千上萬(wàn)個(gè)客戶端連接烈疚,而且性能不會(huì)隨著客戶端的增加而線性下降黔牵。因此,它非常適合做高性能爷肝、高負(fù)載的網(wǎng)絡(luò)服務(wù)器猾浦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市灯抛,隨后出現(xiàn)的幾起案子金赦,更是在濱河造成了極大的恐慌,老刑警劉巖对嚼,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夹抗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡纵竖,警方通過(guò)查閱死者的電腦和手機(jī)漠烧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)杏愤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人沽甥,你說(shuō)我怎么就攤上這事声邦》Π拢” “怎么了摆舟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)邓了。 經(jīng)常有香客問(wèn)我恨诱,道長(zhǎng),這世上最難降的妖魔是什么骗炉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任照宝,我火速辦了婚禮,結(jié)果婚禮上句葵,老公的妹妹穿的比我還像新娘厕鹃。我一直安慰自己,他們只是感情好乍丈,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布剂碴。 她就那樣靜靜地躺著,像睡著了一般轻专。 火紅的嫁衣襯著肌膚如雪忆矛。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天请垛,我揣著相機(jī)與錄音催训,去河邊找鬼。 笑死宗收,一個(gè)胖子當(dāng)著我的面吹牛漫拭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播混稽,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼采驻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了荚坞?” 一聲冷哼從身側(cè)響起挑宠,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎颓影,沒(méi)想到半個(gè)月后各淀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诡挂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年碎浇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了临谱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奴璃,死狀恐怖悉默,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苟穆,我是刑警寧澤抄课,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站雳旅,受9級(jí)特大地震影響跟磨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜攒盈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一抵拘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧型豁,春花似錦僵蛛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至氏豌,卻和暖如春喉酌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泵喘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工泪电, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纪铺。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓相速,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鲜锚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子突诬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容