JAVA NIO原理剖析

模型解釋:

BIO場景下,客戶端(Client)發起連接請求,服務端接收到請求後,會分配一個業務線程處理這次訪問,執行業務處理,寫入響應流。

無論是服務端還是客戶端,數據的讀寫都是阻塞的。比如,服務端收到客戶端的請求,想要獲取客戶端傳過來的請求參數,就會執行讀操作,此時,如果由於網絡原因導致客戶端寫入數據慢或者服務端接收數據慢,這個過程會非常耗時,此時應用線程就只能阻塞等待數據可讀,這個過程會很浪費CPU資源的。並且,隨着用戶請求的增多,阻塞隊列滿了,而應用線程沒有釋放,就會導致後來的請求被拋棄,得不到處理。

爲什麼會出現這種情況?究其原因,服務端執行讀數據的操作,本質上是CPU向操作系統內核發出一條指令,讓操作系統通過TCP/IP協議,從網絡讀取數據到內核,再從內核到內存中。CPU執行指令速度非常快,而操作系統執行IO的速度遠遠趕不上CPU執行指令的速度,就會導致CPU時間的浪費。

2.NIO通訊模型

模型解釋:

NIO場景下,客戶端(Client)發起請求,服務端接收請求後,並不是直接分配業務線程處理這次請求,而是交給專門的IO線程(JAVA 中的Selector)讀取請求流,當數據準備好以後,纔會交給業務線程執行業務邏輯,最後交給IO線程寫入響應流。

到這裏,讀者可能會有兩個疑問?NIO模型下,IO線程會成爲瓶頸?NIO解決了什麼問題(與BIO相比)?

IO線程會成爲瓶頸嗎?這個問題得從IO線程的底層實現說起,NIO之所以是同步非阻塞,就是因爲底層操作系統支持同步非阻塞,JVM只是通過系統調用本地方法實現同步非阻塞的(本質上是操作系統實現同步非阻塞,而JVM只是通過本地方法執行系統調用而已)。linux系統提供了epoll系統調用,epoll是基於事件驅動方式來實現的(也就是說,底層操作系統準備好了數據,以事件驅動的機制回調通知),而NIO中的Selector的select()方法調用,是通過本地方調用epoll系統調用來實現非阻塞的,最大限度利CPU時間片,所以IO線程的瓶頸也就是硬件瓶頸。

NIO解決了什麼問題?

通過單獨的IO線程,當有可讀、可寫的事件發生的時候再去做讀寫操作,這個時候就不用像BIO那樣一直阻塞等待在那,業務線程就可以被釋放出來做更多的事情。說白了,提高了CPU利用率,讓更少的線程做更多的事。

發佈了70 篇原創文章 · 獲贊 68 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章