摘要:的選擇器允許單個(gè)線程監(jiān)視多個(gè)輸入通道。一旦執(zhí)行的線程已經(jīng)超過(guò)讀取代碼中的某個(gè)數(shù)據(jù)片段,該線程就不會(huì)在數(shù)據(jù)中向后移動(dòng)通常不會(huì)。
1、引言
很多初涉網(wǎng)絡(luò)編程的程序員,在研究Java NIO(即異步IO)和經(jīng)典IO(也就是常說(shuō)的阻塞式IO)的API時(shí),很快就會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題:我什么時(shí)候應(yīng)該使用經(jīng)典IO,什么時(shí)候應(yīng)該使用NIO?
在本文中,將嘗試用簡(jiǎn)明扼要的文字,闡明Java NIO和經(jīng)典IO之間的差異、典型用例,以及這些差異如何影響我們的網(wǎng)絡(luò)編程或數(shù)據(jù)傳輸代碼的設(shè)計(jì)和實(shí)現(xiàn)的。
本文沒(méi)有復(fù)雜理論,也沒(méi)有像網(wǎng)上基它文章一樣千篇一律的復(fù)制粘貼,有的只是接地氣的通俗易懂,希望能給你帶來(lái)幫助。
(本文同步發(fā)布于:http://www.52im.net/thread-26...)
2、相關(guān)文章《Java新一代網(wǎng)絡(luò)編程模型AIO原理及Linux系統(tǒng)AIO介紹》
《Java NIO基礎(chǔ)視頻教程、MINA視頻教程、Netty快速入門視頻》
下表總結(jié)了Java NIO和IO之間的主要區(qū)別。我將在表格后面的部分中詳細(xì)介紹每個(gè)區(qū)別。
3.1 Stream Oriented vs. Buffer Oriented
Java NIO和IO之間的第一個(gè)重要區(qū)別是IO是面向流的,其中NIO是面向緩沖區(qū)的。那么,這意味著什么?
面向流的Java IO意味著您可以從流中一次讀取一個(gè)或多個(gè)字節(jié)。你對(duì)讀取的字節(jié)做什么取決于你。它們不會(huì)緩存在任何地方。此外,您無(wú)法在流中的數(shù)據(jù)中前后移動(dòng)。如果需要在從流中讀取的數(shù)據(jù)中前后移動(dòng),則需要先將其緩存在緩沖區(qū)中。
Java NIO的面向緩沖區(qū)的方法略有不同。數(shù)據(jù)被讀入緩沖區(qū),稍后處理該緩沖區(qū)。你可以根據(jù)需要在緩沖區(qū)中前后移動(dòng)。這使你在處理過(guò)程中具有更大的靈活性。但是,你還需要檢查緩沖區(qū)是否包含完整處理所需的所有數(shù)據(jù)。并且,你需要確保在將更多數(shù)據(jù)讀入緩沖區(qū)時(shí),不要覆蓋尚未處理的緩沖區(qū)中的數(shù)據(jù)。
3.2 Blocking vs. Non-blocking IO
Java IO的各種流都是blocking的。這意味著,當(dāng)線程調(diào)用read()或write()時(shí),該線程將被阻塞,直到有一些數(shù)據(jù)要讀取,或者數(shù)據(jù)被完全寫入,在此期間,該線程無(wú)法執(zhí)行任何其他操作。
Java NIO的非阻塞模式允許線程請(qǐng)求從通道讀取數(shù)據(jù),并且只獲取當(dāng)前可用的內(nèi)容,或者根本沒(méi)有數(shù)據(jù),如果當(dāng)前沒(méi)有數(shù)據(jù)可用。線程可以繼續(xù)使用其他內(nèi)容,而不是在數(shù)據(jù)可供讀取之前保持阻塞狀態(tài)。
非阻塞寫入也是如此,線程可以請(qǐng)求將某些數(shù)據(jù)寫入通道,但不要等待它完全寫入。然后線程可以繼續(xù)并在同一時(shí)間做其他事情。
線程在IO調(diào)用中沒(méi)有阻塞時(shí)花費(fèi)空閑時(shí)間,通常在此期間在其他通道上執(zhí)行IO。也就是說(shuō),單個(gè)線程現(xiàn)在可以管理多個(gè)輸入和輸出通道。
4、SelectorsJava NIO的選擇器允許單個(gè)線程監(jiān)視多個(gè)輸入通道。你可以使用選擇器注冊(cè)多個(gè)通道,然后使用單個(gè)線程“選擇”具有可用于處理的輸入的通道,或者選擇準(zhǔn)備寫入的通道。這種選擇器機(jī)制使單個(gè)線程可以輕松管理多個(gè)通道。
5、NIO和經(jīng)典IO如何影響應(yīng)用程序的設(shè)計(jì)?選擇NIO或IO作為IO工具包可能會(huì)影響應(yīng)用程序設(shè)計(jì)的以下方面:
1)API調(diào)用NIO或IO類;
2)處理數(shù)據(jù);
3)用于處理數(shù)據(jù)的線程數(shù)。
5.1 API調(diào)用
當(dāng)然,使用NIO時(shí)的API調(diào)用看起來(lái)與使用IO時(shí)不同。這并不奇怪。而不是僅僅從例如InputStream讀取字節(jié)的數(shù)據(jù)字節(jié),必須首先將數(shù)據(jù)讀入緩沖區(qū),然后從那里進(jìn)行處理。
5.2 數(shù)據(jù)處理
使用純NIO設(shè)計(jì)與IO設(shè)計(jì)時(shí),數(shù)據(jù)處理也會(huì)受到影響。
在IO設(shè)計(jì)中,您從InputStream或Reader中讀取字節(jié)的數(shù)據(jù)字節(jié)。想象一下,您正在處理基于行的文本數(shù)據(jù)流。
例如:
Name: Anna Age: 25 Email: [url=mailto:anna@mailserver.com]anna@mailserver.com[/url] Phone: 1234567890
這個(gè)文本行流可以像這樣處理:
InputStream input = ... ; // get the InputStream from the client socket BufferedReader reader = newBufferedReader(newInputStreamReader(input)); String nameLine = reader.readLine(); String ageLine = reader.readLine(); String emailLine = reader.readLine(); String phoneLine = reader.readLine();
注意處理狀態(tài)是如何,由程序執(zhí)行的程度決定的。換句話說(shuō),一旦第一個(gè)reader.readLine()方法返回,您就確定已經(jīng)讀取了整行文本。readLine()會(huì)阻塞直到讀取整行,這就是原因。您還知道此行包含名稱。同樣,當(dāng)?shù)诙€(gè)readLine()調(diào)用返回時(shí),您知道此行包含年齡等。
正如您所看到的,只有當(dāng)有新數(shù)據(jù)要讀取時(shí),程序才會(huì)進(jìn)行,并且對(duì)于每個(gè)步驟,您都知道該數(shù)據(jù)是什么。一旦執(zhí)行的線程已經(jīng)超過(guò)讀取代碼中的某個(gè)數(shù)據(jù)片段,該線程就不會(huì)在數(shù)據(jù)中向后移動(dòng)(通常不會(huì))。
此圖中還說(shuō)明了此原則:
▲ Java IO:從阻塞流中讀取數(shù)據(jù)
NIO的實(shí)現(xiàn)看起來(lái)會(huì)有所不同,這是一個(gè)簡(jiǎn)化的例子:
ByteBuffer buffer = ByteBuffer.allocate(48);
intbytesRead = inChannel.read(buffer);
注意第二行從通道讀取字節(jié)到ByteBuffer。當(dāng)該方法調(diào)用返回時(shí),您不知道所需的所有數(shù)據(jù)是否都在緩沖區(qū)內(nèi)。你只知道緩沖區(qū)包含一些字節(jié),這使得處理更加困難。
想象一下,在第一次讀?。ň彌_)調(diào)用之后,是否所有讀入緩沖區(qū)的內(nèi)容都是半行。例如,“姓名:An”。你能處理這些數(shù)據(jù)嗎?并不是的。在完成任何數(shù)據(jù)的處理之前,您需要等待至少一整行數(shù)據(jù)進(jìn)入緩沖區(qū)。
那么你怎么知道緩沖區(qū)是否包含足夠的數(shù)據(jù)來(lái)處理它?好吧,你沒(méi)有。找出的唯一方法是查看緩沖區(qū)中的數(shù)據(jù)。結(jié)果是,在您知道所有數(shù)據(jù)是否存在之前,您可能需要多次檢查緩沖區(qū)中的數(shù)據(jù)。這既低效又可能在程序設(shè)計(jì)方面變得混亂。
例如:
ByteBuffer buffer = ByteBuffer.allocate(48);
intbytesRead = inChannel.read(buffer);
while(! bufferFull(bytesRead) ) {
bytesRead = inChannel.read(buffer);
}
bufferFull()方法必須跟蹤讀入緩沖區(qū)的數(shù)據(jù)量,并返回true或false,具體取決于緩沖區(qū)是否已滿。換句話說(shuō),如果緩沖區(qū)已準(zhǔn)備好進(jìn)行處理,則認(rèn)為它已滿。
bufferFull()方法掃描緩沖區(qū),但必須使緩沖區(qū)保持與調(diào)用bufferFull()方法之前相同的狀態(tài)。如果不是,則可能無(wú)法在正確的位置讀入讀入緩沖區(qū)的下一個(gè)數(shù)據(jù)。這不是不可能的,但這是另一個(gè)需要注意的問(wèn)題。
如果緩沖區(qū)已滿,則可以對(duì)其進(jìn)行處理。如果它不滿,您可能能夠部分處理那里的任何數(shù)據(jù),如果這在您的特定情況下是有意義的。在許多情況下,它沒(méi)有。
這個(gè)圖中說(shuō)明了is-data-in-buffer-ready循環(huán):
▲ Java NIO:從通道讀取數(shù)據(jù),直到所有需要的數(shù)據(jù)都在緩沖區(qū)中
6、什么時(shí)候該用NIO?什么時(shí)候該用經(jīng)典IO?NIO允許您僅使用一個(gè)(或幾個(gè))線程來(lái)管理多個(gè)通道(網(wǎng)絡(luò)連接或文件),但成本是解析數(shù)據(jù)可能比從阻塞流中讀取數(shù)據(jù)時(shí)更復(fù)雜。
如果您需要同時(shí)管理數(shù)千個(gè)打開的連接,每個(gè)只發(fā)送一些數(shù)據(jù),例如聊天服務(wù)器,在NIO中實(shí)現(xiàn)服務(wù)器可能是一個(gè)優(yōu)勢(shì)。同樣,如果您需要與其他計(jì)算機(jī)保持大量開放連接,例如在P2P網(wǎng)絡(luò)中,使用單個(gè)線程來(lái)管理所有出站連接可能是一個(gè)優(yōu)勢(shì)。
此圖中說(shuō)明了這一個(gè)線程,多個(gè)連接設(shè)計(jì):
▲ Java NIO:管理多個(gè)連接的單個(gè)線程
如果您擁有較少帶寬的連接,一次發(fā)送大量數(shù)據(jù),那么可能最經(jīng)典的IO服務(wù)器實(shí)現(xiàn)可能是最合適的。
此圖說(shuō)明了經(jīng)典的IO服務(wù)器設(shè)計(jì):
▲ Java IO:經(jīng)典的IO服務(wù)器設(shè)計(jì) - 由一個(gè)線程處理的一個(gè)連接
7、更簡(jiǎn)化的理解以眾所周之的數(shù)據(jù)讀取過(guò)程為例,我們來(lái)一個(gè)更簡(jiǎn)化的理解。
對(duì)于數(shù)據(jù)讀取,就讀取速度來(lái)說(shuō):CPU > 內(nèi)存 > 硬盤。
I- 就是從硬盤到內(nèi)存
O- 就是從內(nèi)存到硬盤
第一種方式:從硬盤讀取數(shù)據(jù),然后程序一直等,數(shù)據(jù)讀完后,繼續(xù)你的操作。這種方式是最簡(jiǎn)單的,叫阻塞IO(也就是經(jīng)典IO)。
第二種方式:從硬盤讀取數(shù)據(jù),然后程序繼續(xù)向下執(zhí)行,等數(shù)據(jù)讀取完后,通知當(dāng)前程序讀取完成(對(duì)硬件來(lái)說(shuō)叫中斷,對(duì)程序來(lái)說(shuō)叫回調(diào)),然后此程序可以立即處理讀取的數(shù)據(jù),也可以執(zhí)行完當(dāng)前操作后再對(duì)讀取完的數(shù)據(jù)進(jìn)行操作。
8、總而言之還是以數(shù)據(jù)讀取為例,操作系統(tǒng)是按塊Block(塊)從硬盤拿數(shù)據(jù),就如同一個(gè)大臉盆,一下子就放入了一盆水。但是,當(dāng) Java 使用的時(shí)候,舊的 IO(經(jīng)典IO)確實(shí)基于 流 Stream的,也就是雖然操作系統(tǒng)給我了一臉盆水,但是我得用吸管慢慢喝。
由于經(jīng)典IO的重重落后理念,于是,NIO 橫空出世。。。
附錄:更多NIO異步網(wǎng)絡(luò)編程資料《Java新一代網(wǎng)絡(luò)編程模型AIO原理及Linux系統(tǒng)AIO介紹》
《有關(guān)“為何選擇Netty”的11個(gè)疑問(wèn)及解答》
《開源NIO框架八卦——到底是先有MINA還是先有Netty?》
《選Netty還是Mina:深入研究與對(duì)比(一)》
《選Netty還是Mina:深入研究與對(duì)比(二)》
《NIO框架入門(一):服務(wù)端基于Netty4的UDP雙向通信Demo演示》
《NIO框架入門(二):服務(wù)端基于MINA2的UDP雙向通信Demo演示》
《NIO框架入門(三):iOS與MINA2、Netty4的跨平臺(tái)UDP雙向通信實(shí)戰(zhàn)》
《NIO框架入門(四):Android與MINA2、Netty4的跨平臺(tái)UDP雙向通信實(shí)戰(zhàn)》
《Netty 4.x學(xué)習(xí)(一):ByteBuf詳解》
《Netty 4.x學(xué)習(xí)(二):Channel和Pipeline詳解》
《Netty 4.x學(xué)習(xí)(三):線程模型詳解》
《Apache Mina框架高級(jí)篇(一):IoFilter詳解》
《Apache Mina框架高級(jí)篇(二):IoHandler詳解》
《MINA2 線程原理總結(jié)(含簡(jiǎn)單測(cè)試實(shí)例)》
《Apache MINA2.0 開發(fā)指南(中文版)[附件下載]》
《MINA、Netty的源代碼(在線閱讀版)已整理發(fā)布》
《解決MINA數(shù)據(jù)傳輸中TCP的粘包、缺包問(wèn)題(有源碼)》
《解決Mina中多個(gè)同類型Filter實(shí)例共存的問(wèn)題》
《實(shí)踐總結(jié):Netty3.x升級(jí)Netty4.x遇到的那些坑(線程篇)》
《實(shí)踐總結(jié):Netty3.x VS Netty4.x的線程模型》
《詳解Netty的安全性:原理介紹、代碼演示(上篇)》
《詳解Netty的安全性:原理介紹、代碼演示(下篇)》
《詳解Netty的優(yōu)雅退出機(jī)制和原理》
《NIO框架詳解:Netty的高性能之道》
《Twitter:如何使用Netty 4來(lái)減少JVM的GC開銷(譯文)》
《絕對(duì)干貨:基于Netty實(shí)現(xiàn)海量接入的推送服務(wù)技術(shù)要點(diǎn)》
《Netty干貨分享:京東京麥的生產(chǎn)級(jí)TCP網(wǎng)關(guān)技術(shù)實(shí)踐總結(jié)》
《新手入門:目前為止最透徹的的Netty高性能原理和框架架構(gòu)解析》
《寫給初學(xué)者:Java高性能NIO框架Netty的學(xué)習(xí)方法和進(jìn)階策略》
《少啰嗦!一分鐘帶你讀懂Java的NIO和經(jīng)典IO的區(qū)別》
更多同類文章 ……
(本文同步發(fā)布于:http://www.52im.net/thread-26...)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/74991.html
摘要:導(dǎo)讀閱讀本文需要有足夠的時(shí)間,筆者會(huì)由淺到深帶你一步一步了解一個(gè)資深架構(gòu)師所要掌握的各類知識(shí)點(diǎn),你也可以按照文章中所列的知識(shí)體系對(duì)比自身,對(duì)自己進(jìn)行查漏補(bǔ)缺,覺(jué)得本文對(duì)你有幫助的話,可以點(diǎn)贊關(guān)注一下。目錄一基礎(chǔ)篇二進(jìn)階篇三高級(jí)篇四架構(gòu)篇五擴(kuò) 導(dǎo)讀:閱讀本文需要有足夠的時(shí)間,筆者會(huì)由淺到深帶你一步一步了解一個(gè)資深架構(gòu)師所要掌握的各類知識(shí)點(diǎn),你也可以按照文章中所列的知識(shí)體系對(duì)比自身,對(duì)自己...
摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對(duì)應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。,織入,將作用在的過(guò)程。因?yàn)樵创a都是英文寫的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下...
摘要:基本介紹選擇式排序也屬于內(nèi)部排序法,是從欲排序的數(shù)據(jù)中,按指定的規(guī)則選出某一元素,再依規(guī)定交換位置后達(dá)到排序的目的。而移動(dòng)次數(shù)與序列的初始排序有關(guān)。空間復(fù)雜度簡(jiǎn)單選擇排序需要占用個(gè)臨時(shí)空間,在交換數(shù)值時(shí)使用。 showImg(https://img-blog.csdnimg.cn/20190509221741422.gif); showImg(https://segmentfault....
閱讀 3352·2023-04-25 16:50
閱讀 981·2021-11-25 09:43
閱讀 3638·2021-09-26 10:11
閱讀 2577·2019-08-26 13:28
閱讀 2589·2019-08-26 13:23
閱讀 2493·2019-08-26 11:53
閱讀 3635·2019-08-23 18:19
閱讀 3052·2019-08-23 16:27