網絡編程的基本模型是Client/Server模型,也就是兩個進程之間進行相互通訊,其中服務端提供位置信息(綁定的IP地址和監聽端口),客戶端經過鏈接操做向服務端監聽的地址發起鏈接請求,經過三次握手創建鏈接,若是鏈接創建成功,雙方就能夠經過網絡套接字(Socket)進行通訊。html
在基於傳統同步阻塞模型開發中,ServerSocket負責綁定IP地址,啓動監聽端口,Socket負責發起鏈接操做,鏈接成功以後,雙方經過輸入和輸出流進行同步阻塞式通訊。java
BIO通訊模型圖編程
BIO的服務端通訊模型:採用BIO通訊模型的服務端,一般由一個獨立的Acceptor線程負責監聽客戶端的鏈接,它接收到客戶端鏈接請求以後爲每一個客戶端建立一個新的線程進行鏈路處理,處理完成以後,經過輸出流返回應答給客戶端,線程銷燬。這就是典型的一請求一應答通訊模型。 segmentfault
該模型最大的問題就是缺少彈性伸縮能力,當客戶端併發訪問量增長後,服務端的線程個數和客戶端併發訪問數呈1:1的正比關係,因爲線程是JAVA虛擬機很是寶貴的系統資源,當線程數膨脹以後,系統的性能將急劇降低,隨着併發訪問量的繼續增大,系統會發生線程堆棧溢出、建立新線程失敗等問題,並最終致使進程宕機或者僵死,不能對外提供服務。後端
它的弊端有不少:服務器
1.性能問題:一鏈接一線程模型致使服務端的併發接入數和系統吞吐量受到極大限制;網絡
2.可靠性問題:因爲I/O操做採用同步阻塞模式,當網絡擁塞或者通訊對端處理緩慢會致使I/O線程被掛住,阻塞時間沒法預測;多線程
3.可維護性問題:I/O線程數沒法有效控制、資源沒法有效共享(多線程併發問題),系統可維護性差;併發
爲了解決同步阻塞IO面臨的一個鏈路須要一個線程處理的問題,後來有人對它的線程模型進行了優化,後端經過一個線程池來處理多個客戶端的請求接入,造成客戶端個數M:線程池最大線程數N的比例關係,其中M能夠遠遠大於N,經過線程池能夠靈活的調配線程資源,設置線程的最大值,防止因爲海量併發接入致使線程耗盡。 下面,咱們結合鏈接模型圖和源碼,對僞異步IO進行分析,看它是否可以解決同步阻塞IO面臨的問題。框架
僞異步IO模型圖
採用線程池和任務隊列能夠實現一種叫作僞異步的IO通訊框架,它的模型圖以下:
當有新的客戶端接入的時候,將客戶端的Socket封裝成一個Task(該任務實現java.lang.Runnable接口)投遞到後端的線程池中進行處理,JDK的線程池維護一個消息隊列和N個活躍線程對消息隊列中的任務進行處理。因爲線程池能夠設置消息隊列的大小和最大線程數,所以,它的資源佔用是可控的,不管多少個客戶端併發訪問,都不會致使資源的耗盡和宕機。
Java NIO的實現關鍵是經過多路複用IO技術實現的,多路複用的核心就是經過Selector來輪詢註冊在其上的Channel,當發現某個或者多個Channel處於就緒狀態後,從阻塞狀態返回就緒的Channel的選擇鍵集合,進行IO操做。
全部的 IO 在NIO 中都從一個Channel 開始。Channel 有點象流。 數據能夠從Channel讀到Buffer中,也能夠從Buffer 寫到Channel中。
Selector容許單線程處理多個Channel。若是你的應用打開了多個鏈接(通道),但每一個鏈接的流量都很低,使用Selector就會很方便。例如,在一個聊天服務器中。
這是在一個單線程中使用一個Selector處理3個Channel的圖示:
BIO | NIO | AIO 以Java的角度,理解以下:
1 BIO模型中經過Socket和ServerSocket完成套接字通道實現。阻塞,同步,鏈接耗時。
2 NIO模型中經過SocketChannel和ServerSocketChannel完成套接字通道實現。非阻塞/阻塞,同步,避免TCP創建鏈接使用三次握手帶來的開銷。
3 AIO模型中經過AsynchronousSocketChannel和AsynchronousServerSocketChannel完成套接字通道實現。非阻塞,異步
BIO 阻塞同步通訊模式,客戶端和服務器鏈接須要三次握手,使用簡單,但吞吐量小
NIO 非阻塞同步通訊模式,客戶端與服務器經過Channel鏈接,採用多路複用器輪詢註冊的Channel。提升吞吐量和可靠性。
AIO 非阻塞異步通訊模式,NIO的升級版,採用異步通道實現異步通訊,其read和write方法均是異步方法。