Java1.4 以前的早期版本,對 I/O 的支持存在以下問題:linux
根據 UNIX 網絡編程對 I/O 模型的分類,UNIX 提供了 5 種 I/O 模型:正則表達式
對於一個套接口上的輸入操做,一般包括2個階段:編程
最經常使用的 I/O 模型就是阻塞 I/O 模型,缺省情形下,全部文件操做都是阻塞的。咱們以套接字接口爲例來說解此模型:在進程空間中調用 recvfrom,其系統調用直到數據包到達且被複制到應用進程的緩衝區中或者發生錯誤時才返回,在此期間一直會等待,進程在從調用 recvfrom 開始到它返回的整段時間內都是被阻塞的,所以被稱爲阻塞 I/O 模型。服務器
recvfrom 從應用層到內核的時候,若是該緩衝區沒有數據的話,就直接返回一個 EWOULDBLOCK 錯誤,通常都對非阻塞 I/O 模型進行輪詢檢查這個狀態,看內核是否是有數據到來。網絡
Linux 提供 select/poll,進程經過將一個或多個 fd 傳遞給 select 或 poll 系統調用,阻塞在 select 操做上,這樣 select/poll 能夠幫咱們偵測多個 fd 是否處於就緒狀態。select/poll 是順序掃描 fd 是否就緒,並且支持的 fd 數量有限,所以它的使用收到了一些制約。Linux 還提供了一個 epoll 系統調用,epoll 使用基於事件驅動方式代替順序掃描,所以性能更高。當有 fd 就緒時,當即回調函數 rollback。多線程
首先開啓套接口信號驅動 I/O 功能,並經過系統調用 sigaction 執行一個信號處理函數(此係統調用當即返回,進程繼續工做,它是非阻塞的)。當數據準備就緒時,就爲該進程生成一個 SIGIO 信號,經過信號回調通知應用程序調用 recvfrom 來讀取數據,並通知主循環函數處理數據。併發
告知內核啓動某個操做,並讓內核在整個操做完成後(包括將數據從內核複製到用戶本身的緩衝區)通知咱們。這種模型與信號驅動模型的主要區別是:信號驅動 I/O 由內核通知咱們什麼時候能夠開始一個 I/O 操做;異步 I/O 模型由內核通知咱們 I/O 操做什麼時候已經完成。異步
5種 I/O 模型比較
socket
在 I/O 編程過程當中,當須要處理多個客戶端接入請求時,能夠利用多線程或者 I/O 多路複用技術進行處理。I/O 多路複用技術經過把多個 I/O 的阻塞複用到同一個 select 的阻塞上,從而使得系統在單線程的狀況下能夠同時處理多個客戶端請求。與傳統的多線程/多進程模型比,I/O 多路複用的最大優點是系統開銷小,系統不須要建立新的額外進程或者線程,也不須要維護這些進程和線程的運行,下降了系統的維護工做量,節省了系統資源。
I/O 多路複用的主要應用場景以下:
目前支持 I/O 多路服用的系統調用有 select、pselect、poll、epoll,在 Linux 網絡編程過程當中,很長一段時間都使用 select 作輪詢和網絡事件通知。爲了克服 select 的缺點,epoll 做了很大的改進:
注:epoll 是 Linux 內核爲處理大批量文件描述符而做了改進的 poll,是 Linux 下多路複用 IO接口 select/poll 的加強版本,它能顯著提升程序在大量併發鏈接中只有少許活躍的狀況下的系統 CPU 利用率。
從JDK1.0 到 JDK1.3,Java 的 I/O 類庫都很是原始,不少 UNIX 網絡編程中的概念或者接口在 I/O 類庫中都沒有體現,例如 Pipe、Channel、Buffer 和 Selector 等。
2002年發佈的 JDK1.4 時,NIO 以 JSR-51 的身份正式隨 JDK 發佈。它新增了個 java.nio 包,提供了不少進行異步 I/O 開發的 API 和類庫,主要的類和接口以下:
2011年7月28日,JDK1.7 正式發佈,將原來的 NIO 類庫進行了升級,被稱爲 NIO2.0。主要包括以下三個方面的改進: