BIO
這個其實就是最傳統的網絡通信模型,就是BIO,同步阻塞式IO,簡單來說大家如果參加過幾個月的培訓班兒應該都知道這種BIO網絡通信方式。就是服務端創建一個ServerSocket,然后客戶端用一個Socket去連接那個ServerSocket,然后ServerSocket接收到一個Socket的連接請求就創建一個Socket和一個線程去跟那個Socket進行通信。
然后客戶端和服務端的Socket,就進行同步阻塞式的通信,客戶端Socket發送一個請求,服務端 Socket進行處理后返回響應,響應必須是等處理完后才會返回,在這之前啥事兒也干不了,這可不就是同步么。
這種方式最大的坑在於,每次一個客戶端接入,都是要在服務端創建一個線程來服務這個客戶端的,這會導致大量的客戶端的時候,服務端的線程數量可能達到幾千甚至幾萬,幾十萬,這會導致服務器端程序的負載過高,最后崩潰死掉。
要么你就是搞一個線程池,固定線程數量來處理請求,但是高並發請求的時候,還是可能會導致各種排隊和延時,因為沒那么多線程來處理。
NIO
JDK1.4中引入了NIO,這是一種同步非阻塞的IO,基於Reactor模型。
NIO中有一些概念:
比如Buffer,緩沖區的概念,一般都是將數據寫入Buffer中,然后從Buffer中讀取數據,有IntBuffer、LongBuffer、CharBuffer等很多種針對基礎數據類型的Buffer。
還有Channel,NIO中都是通過Channel來進行數據讀寫的。
包括Selector,這是多路復用器,selector會不斷輪詢注冊的channel,如果某個channel上發生了讀寫事件,selector就會將這些channel獲取出來,我們通過SelectionKey獲取有讀寫事件的channel,就可以進行IO操作。一個Selector就通過一個線程,就可以輪詢成千上萬的channel,這就意味着你的服務端可以接入成千上萬的客戶端。
這塊其實相當於就是一個線程處理大量的客戶端的請求,通過一個線程輪詢大量的channel,每次就獲取一批有事件的channel,然后對每個請求啟動一個線程處理即可。
這里的核心就是非阻塞,就那個selector一個線程就可以不停輪詢channel,所有客戶端請求都不會阻塞,直接就會進來,大不了就是等待一下排着隊而已。
這里的核心就是因為,一個客戶端不是時時刻刻都要發送請求的,沒必要死耗着一個線程不放吧,所以NIO的優化思想就是一個請求一個線程。只有某個客戶端發送了一個請求的時候,才會啟動一個線程來處理。
所以為啥是非阻塞呢?因為無論多少客戶端都可以接入服務端,客戶端接入並不會耗費一個線程,只會創建一個連接然后注冊到selector上去罷了,一個selector線程不斷的輪詢所有的socket連接,發現有事件了就通知你,然后你就啟動一個線程處理一個請求即可,但是這個處理的過程中,你還是要先讀取數據,處理,再返回的,這是個同步的過程。
所以NIO是同步非阻塞的。
AIO
AIO是基於Proactor模型的,就是異步非阻塞模型。
每個連接發送過來的請求,都會綁定一個buffer,然后通知操作系統去異步完成讀,此時你的程序是會去干別的事兒的,等操作系統完成數據讀取之后,就會回調你的接口,給你操作系統異步讀完的數據。
然后你對這個數據處理一下,接着將結果往回寫。
寫的時候也是給操作系統一個bufer,讓操作系統自己獲取數據去完成寫操作,寫完以后再回來通知你。
工作線程,讀取數據的時候,是說,你提供給操作系統一個buffer,空的,然后你就可以干別的事兒了,你就把讀數據的事兒,交給操作系統去干,操作系統內核,讀數據將數據放入buffer中,完事兒了,來回調你的一個接口,告訴你說,ok,bufer交給你了,這個數據我給你讀好了
寫數據的時候也是一樣的的,把放了數據的buffer交給操作系統的內核去處理,你就可以去干別的事兒了,操作系統完成了數據的寫之后,就會來回調你,告訴你說,ok,哥兒們,你交給我的數據,我都給你寫回到客戶端去了
同步阻塞、同步非阻塞、異步非阻塞
但是這里為啥叫BIO是同步阻塞呢?這個其實不是針對網絡編程模型來說的,是針對文件IO操作來說的,因為用BIO的流讀寫文件,是說你發起個IO請求直接hang死,必須等看搞完了這次IO才能返回。
NIO為啥是同步非阻塞?就是說通過NIO的FileChannel發起個文件IO操作,其實發起之后就返回了,你可以干別的事兒,這就是非阻塞,但是接下來你還得不斷的去輪詢操作系統,看IO操作完事兒了沒有。
AIO為啥是異步非阻塞?就是說通過AIO發起個文件IO操作之后,你立馬就返回可以干別