Java IO 1 涉及到的底層概念

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)

blocking-IO.png

調用過程:

  1. 用戶進程調用一個recvfrom請求,內核收到這個請求之后沒有立即返回,而是首先等待數據到達。

  2. 等數據到達之后,再進行數據拷貝,將數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。

上面整個過程都是阻塞的。

2) nonblocking IO(非阻塞IO)

noblocking-IO.png

調用過程:

  1. 用戶進程調用一個recvfrom請求,內核收到這個請求之后立即返回數據沒有到達的消息。

  2. 用戶進程收到消息后繼續發送recvfrom請求,如果數據仍沒有到達,內核繼續返回沒有到達的消息。

  3. 如此循環,直到數據到達內核。然后內核將收到的數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。

上面整個過程都是阻塞的。

3) IO multiplexing(IO復用) (select/poll/epoll)

IO-multiplexing.png

調用過程:

  1. 用戶進程通過調用select或poll或epoll去查詢多個文件描述符的狀態。

  2. 如果有一個文件描述符準備好了,內核就返回該文件描述符可讀的消息。

  3. 用戶進程調用一個recvfrom請求,內核收到請求后開始拷貝數據,將數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。

上面整個過程都是阻塞的。

  1. signal driven IO(信號驅動IO)
signal-driven-IO.png

調用過程:

  1. 設置socket為一個信號驅動IO,并且通過sigaction system call安裝一個signal handler。

  2. 數據準備好以后,一個SIGIO信號傳送給用戶進程通知數據已經準備好。

  3. 然后用戶進程調用一個recvfrom請求,內核收到請求后開始拷貝數據,將數據從內核緩存區拷貝到用戶進程緩存區,拷貝完成后返回給進程ok的消息。

步驟1因為是瞬時完成的,可以認為是非阻塞的。步驟2,3是阻塞的。

  1. asynchronous IO(異步IO)
asynchronous-IO.png

調用過程:

  1. 用戶進程發送一個aio_read的系統調用,內核立即返回響應。

  2. 用戶進程收到響應,可以繼續做自己的事(非阻塞)。

  3. 內核等待數據到達,完成數據拷貝后,發送消息給用戶進程。

上面整個過程都是非阻塞的。

三 windowsIO模型

windwos IO模型感覺和linuxIO模型相似,感興趣的同學可以看看這個

ps: 本文的圖和英文引用部分來自參考文檔3.中文引用部分來自文檔1(參考文檔寫的比我好,建議大家多看看 :))

參考文檔:

  1. Linux下的五種IO模型

  2. 從內核文件系統看文件讀寫過程

  3. Linux_Programming/UNIX Network Programming(Volume1,3rd).pdf

  4. 使用異步 I/O 大大提高應用程序的性能

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容