淺談 Java 中的 IO 和 NIO

????????首先,我們先澄清一些基本概念:1,區(qū)分同步或異步(synchronous/asynchronous)。簡(jiǎn)單的說,同步是一種可靠的有序運(yùn)行機(jī)制,當(dāng)我們進(jìn)行同步操作時(shí),后續(xù)的任務(wù)是等待當(dāng)前調(diào)用返回,才會(huì)進(jìn)行下一步;而異步則相反,其他任務(wù)不需要等待當(dāng)前調(diào)用返回,通常依靠事件,回調(diào)等機(jī)制來實(shí)現(xiàn)任務(wù)間次序關(guān)系。2,區(qū)分阻塞與非阻塞(blocking/non-blocking)。在進(jìn)行阻塞操作時(shí),當(dāng)前線程會(huì)處于阻塞狀態(tài),無法從事其他任務(wù),只有當(dāng)條件就緒才能繼續(xù),比如 ServerSocket 新連接建立完畢,或數(shù)據(jù)讀取,寫入操作完成;而非阻塞則是不管 IO 操作是否結(jié)束,直接返回,相應(yīng)操作在后臺(tái)繼續(xù)處理。不能一概而論認(rèn)為同步或阻塞就是低效,具體還要看應(yīng)用和系統(tǒng)特征。

第一,IO?

? ? ? ? Java IO 有很多種,基于不同的 IO 抽象模型和交互方式,可以進(jìn)行簡(jiǎn)單區(qū)分。首先,傳統(tǒng)的 java,io 包,它基于流模型實(shí)現(xiàn),提供了我們最熟知的一些 IO 功能,比如 File 抽象,輸入輸出流等。交互方式是同步,阻塞的方式,也就是說,在讀取輸入流或者寫入輸出流時(shí),在讀,寫動(dòng)作完成之前,線程會(huì)一直阻塞在哪里,它們之間的調(diào)用時(shí)可靠的線性順序。java.io 包的好處是代碼比較簡(jiǎn)單,直觀,缺點(diǎn)是 IO 效率和擴(kuò)展性存在局限性,容易成為應(yīng)用性能的瓶頸。很多時(shí)候,大家把 java.net 下面提供的部分網(wǎng)絡(luò) API,比如 Socket,ServerSocket,HttpURLConnection 也歸類到同步阻塞 IO 類庫,因?yàn)榫W(wǎng)絡(luò)通信同樣是 IO 行為。

? ? ? ? 對(duì)于 IO 的理解我認(rèn)為至少得需要理解下面幾點(diǎn):1, IO 不僅僅是對(duì)文件的操作,網(wǎng)絡(luò)編程中,比如 Socket 通信,都是典型的 IO 操作目標(biāo)。2,輸入/輸出流(InputStreanm/OutputStream)是用于讀取或者寫入字節(jié)的。3,Reader/Writer 則是用于操作字符,增加了字符編解碼等功能,適用于類似從文件中讀取或者寫入文本信息。本質(zhì)上計(jì)算機(jī)操作的都是字節(jié),不管是網(wǎng)絡(luò)通信還是文件讀取,Reader/Writer 相當(dāng)于構(gòu)建了應(yīng)用邏輯和原始數(shù)據(jù)之間的橋梁。4,BufferedOutputStream 等帶緩沖區(qū)的實(shí)現(xiàn),可以避免頻繁的磁盤讀寫,進(jìn)而提高 IO 處理效率。這種設(shè)計(jì)利用了緩沖區(qū),將批量數(shù)據(jù)進(jìn)行一次操作,但在使用中千萬別忘記了 flush。5,很多 IO 工具類都實(shí)現(xiàn)了 Closeable 接口,因?yàn)樾枰M(jìn)行資源的釋放。比如,打開 FileInputStream,它就會(huì)獲取相應(yīng)的文件描述符(FileDescriptor),需要利用 try-with-resources,try-finally 等機(jī)制保證FileInputStream 被明確關(guān)閉,進(jìn)而相應(yīng)文件描述符也會(huì)失效,否則將導(dǎo)致資源無法被釋放。看下圖:

第二,NIO

????????在 java 1.4 中引入了 NIO 框架 (java.nio 包),提供了 Channel,Selector,Buffer 等新的抽象,可以構(gòu)建多路復(fù)用的,同步非阻塞 IO 程序,同時(shí)提供了更接近操作系統(tǒng)底層的高性能數(shù)據(jù)操作方式。在 java 7 中,NIO 有了進(jìn)一步的改進(jìn),也就是 NIO 2,引入了異步非阻塞 IO 方式,也有很多人叫它 AIO(Asynchronous IO)。異步 IO 操作基于事件和回調(diào)機(jī)制,可以簡(jiǎn)單理解為,應(yīng)用操作直接返回,而不是阻塞在哪里,當(dāng)后臺(tái)處理完成,操作系統(tǒng)會(huì)通知相應(yīng)線程進(jìn)行后續(xù)工作。

? ??????對(duì)于 NIO 的理解我認(rèn)為至少得需要理解下面幾部分:1,Buffer,高效的數(shù)據(jù)容器,除了布爾類型,所有原始數(shù)據(jù)類型都有相應(yīng)的 Buffer 實(shí)現(xiàn)。2,Channel,類似在 Linux 之類操作系統(tǒng)上看到的文件描述符,是 NIO 中被用來支持批量式 IO 操作的一種抽象。3,F(xiàn)ile 或者 Socket,通常被認(rèn)為是比較高層次的抽象,而 Channel 則是更加操作系統(tǒng)底層的一種抽象,這也使得 NIO 得以充分利用現(xiàn)代操作系統(tǒng)底層機(jī)制,獲得特定場(chǎng)景的性能優(yōu)化。不同層次的抽象是相互關(guān)聯(lián)的,我們可以通過 Socket 獲取 Channel,反之亦然。4,Selector,是 NIO 實(shí)現(xiàn)多路復(fù)用的基礎(chǔ),它提供了一種高效的機(jī)制,可以檢測(cè)到注冊(cè)在 Selector 上的多個(gè) Channel 中,是否有 Channel 處于就緒狀態(tài),進(jìn)而實(shí)現(xiàn)了單線程對(duì)多 Channel 的高效管理。Selector 同樣基于底層操作系統(tǒng)機(jī)制,不同模式,不同版本都存在區(qū)別。

我是溫馭臣,一個(gè)java的開發(fā)學(xué)習(xí)者,以上是我的簡(jiǎn)單總結(jié),如果有缺陷,希望在評(píng)論區(qū)看到您的補(bǔ)充。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容