JAVA IO/NIO

2.8.1. 阻塞 IO 模型 異步

最傳統的一種 IO 模型,即在讀寫數據過程當中會發生阻塞現象。當用戶線程發出 IO 請求以後,內 核會去查看數據是否就緒,若是沒有就緒就會等待數據就緒,而用戶線程就會處於阻塞狀態,用 戶線程交出 CPU。當數據就緒以後,內核會將數據拷貝到用戶線程,並返回結果給用戶線程,用 13/04/2018 Page 35 of 283 戶線程才解除 block 狀態。典型的阻塞 IO 模型的例子爲:data = socket.read();若是數據沒有就 緒,就會一直阻塞在 read 方法。socket

2.8.2. 非阻塞 IO 模型 async

當用戶線程發起一個 read 操做後,並不須要等待,而是立刻就獲得了一個結果。若是結果是一個 error 時,它就知道數據尚未準備好,因而它能夠再次發送 read 操做。一旦內核中的數據準備 好了,而且又再次收到了用戶線程的請求,那麼它立刻就將數據拷貝到了用戶線程,而後返回。 因此事實上,在非阻塞 IO 模型中,用戶線程須要不斷地詢問內核數據是否就緒,也就說非阻塞 IO 不會交出 CPU,而會一直佔用 CPU。典型的非阻塞 IO 模型通常以下:函數

while(true){ data = socket.read(); if(data!= error){ 處理數據 break; } }操作系統

可是對於非阻塞 IO 就有一個很是嚴重的問題,在 while 循環中須要不斷地去詢問內核數據是否就 緒,這樣會致使 CPU 佔用率很是高,所以通常狀況下不多使用 while 循環這種方式來讀取數據。線程

2.8.3. 多路複用 IO 模型 進程

多路複用 IO 模型是目前使用得比較多的模型。Java NIO 實際上就是多路複用 IO。在多路複用 IO 模型中,會有一個線程不斷去輪詢多個 socket 的狀態,只有當 socket 真正有讀寫事件時,才真 正調用實際的 IO 讀寫操做。由於在多路複用 IO 模型中,只須要使用一個線程就能夠管理多個 socket,系統不須要創建新的進程或者線程,也沒必要維護這些線程和進程,而且只有在真正有 socket 讀寫事件進行時,纔會使用 IO 資源,因此它大大減小了資源佔用。在 Java NIO 中,是通 過 selector.select()去查詢每一個通道是否有到達事件,若是沒有事件,則一直阻塞在那裏,所以這 種方式會致使用戶線程的阻塞。多路複用 IO 模式,經過一個線程就能夠管理多個 socket,只有當 socket 真正有讀寫事件發生纔會佔用資源來進行實際的讀寫操做。所以,多路複用 IO 比較適合連 接數比較多的狀況。 另外多路複用 IO 爲什麼比非阻塞 IO 模型的效率高是由於在非阻塞 IO 中,不斷地詢問 socket 狀態 時經過用戶線程去進行的,而在多路複用 IO 中,輪詢每一個 socket 狀態是內核在進行的,這個效 率要比用戶線程要高的多。 不過要注意的是,多路複用 IO 模型是經過輪詢的方式來檢測是否有事件到達,而且對到達的事件 逐一進行響應。所以對於多路複用 IO 模型來講,一旦事件響應體很大,那麼就會致使後續的事件 遲遲得不處處理,而且會影響新的事件輪詢。 事件

2.8.4. 信號驅動 IO 模型 資源

在信號驅動 IO 模型中,當用戶線程發起一個 IO 請求操做,會給對應的 socket 註冊一個信號函 數,而後用戶線程會繼續執行,當內核數據就緒時會發送一個信號給用戶線程,用戶線程接收到 信號以後,便在信號函數中調用 IO 讀寫操做來進行實際的 IO 請求操做。效率

2.8.5. 異步 IO 模型

異步 IO 模型纔是最理想的 IO 模型,在異步 IO 模型中,當用戶線程發起 read 操做以後,馬上就 能夠開始去作其它的事。而另外一方面,從內核的角度,當它受到一個 asynchronous read 以後, 它會馬上返回,說明 read 請求已經成功發起了,所以不會對用戶線程產生任何 block。而後,內 核會等待數據準備完成,而後將數據拷貝到用戶線程,當這一切都完成以後,內核會給用戶線程 發送一個信號,告訴它 read 操做完成了。也就說用戶線程徹底不須要實際的整個 IO 操做是如何 進行的,只須要先發起一個請求,當接收內核返回的成功信號時表示 IO 操做已經完成,能夠直接 去使用數據了。 也就說在異步 IO 模型中,IO 操做的兩個階段都不會阻塞用戶線程,這兩個階段都是由內核自動完 成,而後發送一個信號告知用戶線程操做已完成。用戶線程中不須要再次調用 IO 函數進行具體的 讀寫。這點是和信號驅動模型有所不一樣的,在信號驅動模型中,當用戶線程接收到信號表示數據 已經就緒,而後須要用戶線程調用 IO 函數進行實際的讀寫操做;而在異步 IO 模型中,收到信號 表示 IO 操做已經完成,不須要再在用戶線程中調用 IO 函數進行實際的讀寫操做。

注意,異步 IO 是須要操做系統的底層支持,在 Java 7 中,提供了 Asynchronous IO。

相關文章
相關標籤/搜索