1、BIOjava
在JDK1.4出來以前,咱們創建網絡鏈接的時候採用BIO模式,須要先在服務端啓動一個ServerSocket,而後在客戶端啓動Socket來對服務端進行通訊,默認狀況下服務端須要對每一個鏈接請求創建一堆線程等待其餘請求操做,而客戶端發送請求後,先諮詢服務端是否有線程相應,若是沒有則會一直等待或者遭到拒絕請求,若是有的話,客戶端鏈接線程會等待請求結束後才繼續執行。後端
在使用同步I/O的網絡應用中,若是要同時處理多個客戶端請求,或是在客戶端要同時和多個服務器進行通信,就必須使用多線程來處理。服務器
也就是說,將每個客戶端請求分配給一個線程來單獨處理。這樣作雖然能夠達到咱們的要求,但同時又會帶來另一個問題。因爲每建立一個線程,就要爲這個線程分配必定的內存空間(也叫工做存儲器),並且操做系統自己也對線程的總數有必定的限制。若是客戶端的請求過多,服務端程序可能會由於不堪重負而拒絕客戶端的請求,甚至服務器可能會所以而癱瘓。網絡
缺點1:
每有一個用戶請求,就會建立一個新的線程。當用戶請求量特別巨大,線程數量要會隨之增 大,繼而內存的佔用增大,因此,不可能適用高併發、高訪問的場景。
缺點2:
線程特別多,不只是佔用內存開銷,也會佔用大量的cpu開銷,由於cpu要作線程調度。
缺點3:
若是一個用戶僅僅是連入操做,而且長時間不作其餘操做,會產生大量的閒置線程。會使cpu 作無心義的空轉。下降總體性能
缺點4:
這個模型會致使真正須要被處理的線程(用戶請求)不能被及時處理多線程
針對缺點3和缺點4,能夠將閒置的線程設置爲阻塞態,cpu是不會調度阻塞態的線程,避免了cpu的空轉。因此引入事件監聽機制實現。併發
Selector多路複用選擇器,起到事件監聽的做用。異步
監聽哪個用戶執行操做,就喚醒對應的線程執行。那麼都有哪些事件呢?socket
事件:1.accept事件、2.connect事件、3.read事件、4.write事件函數
針對缺點1和缺點2,能夠利用非阻塞模型來實現,利用少許線程甚至一個線程來處理多用戶請求。可是注意,這個模型是有使用場景的,適用於大量短請求場景。(好比用戶訪問電商網站),不適合長請求場景(好比下載大文件,這種場景,NIO不見得比BIO好)高併發
2、NIO
NIO自己是基於事件驅動思想來完成的,其主要想解決的是BIO的併發問題:
NIO基於Reactor,當socket有流可讀或可寫入socket時,操做系統會相應的通知引用程序進行處理,應用再將流讀取到緩衝區或寫入操做系統。 也就是說,這個時候,已經不是一個鏈接就要對應一個處理線程了,而是有效的請求,對應一個線程,當鏈接沒有數據時,是沒有工做線程來處理的。
BIO與NIO一個比較重要的不一樣,是咱們使用BIO的時候每每會引入多線程,每一個鏈接一個單獨的線程;而NIO則是使用單線程或者只使用少許的多線程,每一個鏈接共用一個線程。
selector有兩個做用:多路複用和事件監聽
NIO的最重要的地方是當一個鏈接建立後,不須要對應一個線程,這個鏈接會被註冊到多路複用器上面,因此全部的鏈接只須要一個線程就能夠搞定,當這個線程中的多路複用器進行輪詢的時候,發現鏈接上有請求的話,纔開啓一個線程進行處理,也就是一個請求一個線程模式。
在NIO的處理方式中,當一個請求來的話,開啓線程進行處理,可能會等待後端應用的資源(JDBC鏈接等),其實這個線程就被阻塞了,當併發上來的話,仍是會有BIO同樣的問題。
HTTP/1.1出現後,有了Http長鏈接,這樣除了超時和指明特定關閉的http header外,這個連接是一直打開的狀態的,這樣在NIO處理中能夠進一步的進化,在後端資源中能夠實現資源池或者隊列,當請求來的話,開啓的線程把請求和請求數據傳送給後端資源池或者隊列裏面就返回,而且在全局的地方保持住這個現場(哪一個鏈接的哪一個請求等),這樣前面的線程仍是能夠去接受其餘的請求,然後端的應用的處理只須要執行隊列裏面的就能夠了,這樣請求處理和後端應用是異步的.當後端處理完,到全局地方獲得現場,產生響應,這個就實現了異步處理。
3、AIO
與NIO不一樣,當進行讀寫操做時,只須直接調用API的read或write方法便可。這兩種方法均爲異步的,對於讀操做而言,當有流可讀取時,操做系統會將可讀的流傳入read方法的緩衝區,並通知應用程序;對於寫操做而言,當操做系統將write方法傳遞的流寫入完畢時,操做系統主動通知應用程序。 便可以理解爲,read/write方法都是異步的,完成後會主動調用回調函數。 在JDK1.7中,這部份內容被稱做NIO.2,主要在java.nio.channels包下增長了下面四個異步通道:
其中的read/write方法,會返回一個帶回調函數的對象,當執行完讀取/寫入操做後,直接調用回調函數。
BIO是一個鏈接一個線程。
NIO是一個請求一個線程。
AIO是一個有效請求一個線程。
先來個例子理解一下概念,以銀行取款爲例: