本文原創地址,
個人博客
:jsbintask.cn/2019/04/16/…(食用效果最佳),轉載請註明出處!java
在理解什麼是BIO,NIO,AIO以前,咱們首先須要瞭解什麼是同步,異步,阻塞,非阻塞。假如咱們如今要去銀行取錢: 同步
: 本身親自出馬持銀行卡到銀行取錢(使用同步IO時,Java本身處理IO讀寫); 異步
: 委託一小弟拿銀行卡到銀行取錢,而後給你(使用異步IO時,Java將IO讀寫委託給OS處理,須要將數據緩衝區地址和大小傳給OS(銀行卡和密碼),OS須要支持異步IO操做API); 阻塞
: ATM排隊取款,你只能等待(使用阻塞IO時,Java調用會一直阻塞到讀寫完成才返回); 非阻塞
: 櫃檯取款,取個號,而後坐在椅子上作其它事,等號廣播會通知你辦理,沒到號你就不能去,你能夠不斷問大堂經理排到了沒有,大堂經理若是說還沒到你就不能去(使用非阻塞IO時,若是不能讀寫Java調用會立刻返回,當IO事件分發器會通知可讀寫時再繼續進行讀寫,不斷循環直到讀寫完成)編程
Blocking IO
,同步阻塞式IO,jdk1.4之前,一直採用BIO編程模型,在Socket
網絡編程中,咱們一般會使用ServerSocket.accept()
方法獲取一個新鏈接,該方法會阻塞當前主線程,因此一般一個鏈接來了後,會將其放入線程池去執行後續操做。而客戶端發送請求後,先諮詢服務端是否有線程相應,若是沒有則會一直等待或者遭到拒絕請求,若是有的話,客戶端Socket的connect方法一樣會阻塞當前線程等待請求結束後才繼續執行。後端
New IO
,同步非阻塞式IO,jdk1.4後引入,主要用於解決BIO大併發的問題,因爲BIO會爲任何鏈接都分配一個線程,而操做系統資源有限,若是客戶端的請求過多,服務端程序可能會由於不堪重負而拒絕客戶端的請求,甚至服務器可能會所以而癱瘓。服務器
NIO基於Reactor,當socket有流可讀或可寫入socket時,操做系統會相應的通知引用程序進行處理,應用再將流讀取到緩衝區或寫入操做系統。 也就是說,這個時候,已經不是一個鏈接就要對應一個處理線程了,而是有效的請求,對應一個線程,當鏈接沒有數據時,是沒有工做線程來處理的。 網絡
Selector
在不斷輪詢註冊這些新鏈接,當鏈接準備好後,再將其加入線程池。
HTTP/1.1出現後,有了Http長鏈接,這樣除了超時和指明特定關閉的http header外,這個連接是一直打開的狀態的,這樣在NIO處理中能夠進一步的進化,在後端資源中能夠實現資源池或者隊列,當請求來的話,開啓的線程把請求和請求數據傳送給後端資源池或者隊列裏面就返回,而且在全局的地方保持住這個現場(哪一個鏈接的哪一個請求等),這樣前面的線程仍是能夠去接受其餘的請求,然後端的應用的處理只須要執行隊列裏面的就能夠了,這樣請求處理和後端應用是異步的.當後端處理完,到全局地方獲得現場,產生響應,這個就實現了異步處理。併發
對應BIO中的ServerSocket
,Socket
,再NIO中的編程類爲: ServerSocketChannel
, SocketChannel
,值得注意的是,它們的accept()
,connect
方法均不是阻塞的,當沒有鏈接或者鏈接沒有當即創建時,它們都會直接返回,不會阻塞當前線程!異步
值得注意的是,雖然jdk已經爲咱們提供了NIO編程模型,可是使用難度較大,而且存在空輪詢的bug。因此通常咱們會考慮使用在 jdk NIO的基礎上繼續封裝的Netty
!socket
NIO.2
,異步非阻塞IO。jdk1.7引入。與NIO不一樣,當進行讀寫操做時,只須直接調用API的read或write方法便可。這兩種方法均爲異步的,對於讀操做而言,當有流可讀取時,操做系統會將可讀的流傳入read方法的緩衝區,並通知應用程序;對於寫操做而言,當操做系統將write方法傳遞的流寫入完畢時,操做系統主動通知應用程序。 便可以理解爲,read/write方法都是異步的,完成後會主動調用回調函數。 主要在java.nio.channels包下增長了下面四個異步通道: AsynchronousSocketChannel
, AsynchronousServerSocketChannel
, AsynchronousFileChannel
, AsynchronousDatagramChannel
其中的read/write方法,會返回一個帶回調函數的對象,當執行完讀取/寫入操做後,直接調用回調函數。函數
關注我,這裏只有乾貨!
操作系統