Java io的接口經過了多次迭代,現在主要分為三部分,即java IO (since JDK1.0),java NIO(since JDK1.4),java NIO2(since JDK1.7)。
那么java為什么要將IO的接口分成這三部分呢,這三部分的接口又有什么不同呢?
它們背后的底層原理是什么,要怎么樣理解才比較好呢?常常聽到的阻塞,非阻塞,同步,異步的概念,到底它們是什么,之間有什么區別?
本文將試著根據相關的文檔,用自己的語言來解釋這些問題,希望對你有所啟發。
一 涉及的對象
1) 用戶進程和操作系統內核
Java 中的IO可以理解為是在Java程序和操作系統內核兩個對象之間進行的。
后面所說的阻塞和非阻塞,同步和異步都是這兩個對象相互作用的結果。在本文中,用戶進程指的就是Java程序。
2) 程序空間和內核空間
Waiting for the data to be ready(等待數據到達內核緩沖區)
Copying the data from the kernel to the process(從內核緩沖區拷貝數據到程序緩沖區)
在Linux中,對于一次讀取IO的操作,數據并不會直接拷貝到程序的程序緩沖區。
它首先會被拷貝到操作系統內核的緩沖區中,然后才會從操作系統內核的緩沖區拷貝到應用程序的緩沖區。
程序空間:分配給用戶程序的內存空間。
內核空間:內核擁有的內存空間。
3) 阻塞和非阻塞
阻塞:用戶進程進行系統調用后,用戶進程一直處于鎖定的狀態,不能進行其他操作
非阻塞:用戶進程進行系統調用后,用戶進程沒有被鎖定,可以進行其他操作
阻塞和非阻塞說的是用戶進程的狀態,即用戶進程是否被鎖定
4) 同步和異步
A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
An asynchronous I/O operation does not cause the requesting process to be blocked.
一個同步的io操作會導致發起請求的進程阻塞直到這個io操作完成。一個異步的io操作不會導致請求的線程被阻塞。
同步:用戶線程和io線程做同一件事(用戶線程被阻塞,等待內核返回處理結果)
異步:用戶線程和io線程做不同的事情(用戶線程不被阻塞,做其他的事情,內核處理完成發送結果給用戶線程)
5) 文件描述符
在Linux下面一切皆文件。文件描述符(file descriptor)是內核為文件所創建的索引,所有I/O操作都通過調用文件描述符(索引)來執行,包括下面我們要提到的socket。Linux剛啟動的時候會自動設置0是標準輸入,1是標準輸出,2是標準錯誤。
二 uninx五種IO模型
1) blocking IO(阻塞IO)
調用過程:
用戶進程調用一個recvfrom請求,內核收到這個請求之后沒有立即返回,而是首先等待數據到達。
等數據到達之后,再進行數據拷貝,將數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。
上面整個過程都是阻塞的。
2) nonblocking IO(非阻塞IO)
調用過程:
用戶進程調用一個recvfrom請求,內核收到這個請求之后立即返回數據沒有到達的消息。
用戶進程收到消息后繼續發送recvfrom請求,如果數據仍沒有到達,內核繼續返回沒有到達的消息。
如此循環,直到數據到達內核。然后內核將收到的數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。
上面整個過程都是阻塞的。
3) IO multiplexing(IO復用) (select/poll/epoll)
調用過程:
用戶進程通過調用select或poll或epoll去查詢多個文件描述符的狀態。
如果有一個文件描述符準備好了,內核就返回該文件描述符可讀的消息。
用戶進程調用一個recvfrom請求,內核收到請求后開始拷貝數據,將數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。
上面整個過程都是阻塞的。
- signal driven IO(信號驅動IO)
調用過程:
設置socket為一個信號驅動IO,并且通過sigaction system call安裝一個signal handler。
數據準備好以后,一個SIGIO信號傳送給用戶進程通知數據已經準備好。
然后用戶進程調用一個recvfrom請求,內核收到請求后開始拷貝數據,將數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。
步驟1因為是瞬時完成的,可以認為是非阻塞的。步驟2,3是阻塞的。
- asynchronous IO(異步IO)
調用過程:
用戶進程發送一個aio_read的系統調用,內核立即返回響應。
用戶進程收到響應,可以繼續做自己的事(非阻塞)。
內核等待數據到達,完成數據拷貝后,發送消息給用戶進程。
上面整個過程都是非阻塞的。
三 windowsIO模型
windwos IO模型感覺和linuxIO模型相似,感興趣的同學可以看看這個
ps: 本文的圖和英文引用部分來自參考文檔3.中文引用部分來自文檔1(參考文檔寫的比我好,建議大家多看看 :))
參考文檔: