jdk源碼分析 ——Selector深入分析

1、spi方式的selector定製化
selector通過SelectorProvider創建的,通常不同安裝版本的jdk中已經封裝了相應的Select和SelectorProvider了,通過spi的方式進行擴展。(PS:spi是一種jdk提供的低侵入方式的擴展實現,目前已經在大多數的框架中使用了,類似dubbo框架也使用該方式,讓用戶進行更好的定製化實現)

2、selector的原理
NIO極大提高了IO的併發,且在各大操作系統都已經有了相應的支持,類似linux的select、pool、epoll等,windows的IOCP等。在NIO中又包含了兩種機制,一種是reactor;另外一種是proactor,這兩種方式的主要區別是:IO數據是自己去內核讀取,還是提供用戶空間數據緩衝區,讓內核讀取。

在目前的jdk版本中也最大化的利用了操作系統的NIO機制,封裝成了統一的接口供java應用使用,該實現機制是在操作系統的NIO的reactor或者proactor機制之上,再次封裝了一次,並創建相應的socket事件的映射即可。

3、selector多線程特性
在jdk中自帶的selector的方法是線程安全的,可以多線程調用selector的方法,但是從我個人的實踐來看,其實沒有必要多線程調用,其實單個線程就可以了,最主要是select出來的Set這個可以進行多線程的處理,但是該集合是非線程安全的,所以在多線程使用的時候需要進行同步的操作

4、關於多線程accept的理解
爲什麼需要多線程的accept?這個問題需要仔細的分析,目前很多框架都是用了多線程的accept,但是使用多線程的accept是有條件的,那就是在某一個線程accept之後之後,會對新的socket進行一些簡單的認證的操作等,操作完了之後再把該socket放入業務線程池。由於這些操作需要花費一定的時間,所以這個時候可以把serversocket讓出來,讓其他的線程accept。

那麼問題來了:那爲什麼不可以單個線程accept,然後將accept的socket直接丟到業務線程池呢?
其實這樣也是可以的,但是爲了更好的符合單一職責的原則,業務線程池應該是主要負責業務處理的,那麼像socket的一些合法性檢測等操作應該使用單獨的線程池進行,既然有了獨立的線程池,而且這些檢測本身也不是特別耗時,所以就可以把accept也放到該線程中了。

但是在很早之前的操作系統中這種多線程的accept會出現“驚羣”效應,目前很多操作系統已經解決了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章