1. 程式人生 > >Java IO 和 NIO的區別

Java IO 和 NIO的區別

主要區別

IO NIO
面向位元組流 面向緩衝區
阻塞 基於Selector的非阻塞

Java IO 和 NIO的主要區別體現在以上兩個方面,以下詳細說明這些區別的具體含義。

面向流和麵向緩衝區

這個概念和程式設計方法中的面向過程、面向物件類似。Java IO 是面向流的而Java NIO是面向緩衝區的。

在Java IO中讀取資料和寫入資料是面向流(Stream)的,這表示當我們從流中讀取資料,寫入資料時也將其寫入流,流的含義在於沒有快取 ,就好像我們站在流水線前,所有的資料沿著流水線依次到達我們的面前,我們只能讀取當前的資料(相當於我們擁有一個數據流的切面)。如果需要獲取某個資料的前一項或後一項資料那就必須自己快取資料,而不能直接從流中獲取(因為面向流就意味著我們只有一個數據流的切面)

而在Java NIO中資料的讀寫是面向緩衝區(Buffer)的,讀取時可以將整塊的資料讀取到緩衝區中,在寫入時則可以將整個緩衝區中的資料一起寫入。這就好像是將流水線傳輸變成了卡車運送,面向流的資料讀寫只提供了一個數據流切面,而面向緩衝區的IO則使我們能夠看到資料的上下文,也就是說在緩衝區中獲取某項資料的前一項資料或者是後一項資料十分方便。這種便利是有代價的,因為我們必須管理好緩衝區,這包括不能讓新的資料覆蓋了緩衝區中還沒有被處理的有用資料;將緩衝區中的資料正確的分塊,分清哪些被處理過哪些還沒有等等。

Java NIO的IO模型與很多IO的本質更加一致!磁碟IO讀寫就是資料塊讀寫; TCP/IP協議傳輸的也是資料包而不是資料流。但是很多系統提供的是卻是面向流的系統API,例如套接字API是面向資料流的。

阻塞和非阻塞

Java IO是阻塞的,如果在一次讀寫資料呼叫時資料還沒有準備好,或者目前不可寫,那麼讀寫操作就會被阻塞直到資料準備好或目標可寫為止。Java NIO則是非阻塞的,每一次資料讀寫呼叫都會立即返回,並將目前可讀(或可寫)的內容寫入緩衝區或者從緩衝區中輸出,即使當前沒有可用資料,呼叫仍然會立即返回並且不對緩衝區做任何操作。這就好像去超市買東西,如果超市中沒有需要的商品或者數量還不夠,那麼Java IO會一直等直到超市中需要的商品數量足夠了就將所有需要的商品帶回來,Java NIO則不同,不論超市中有多少需要的商品,它都會立即買下可以買到的所有需要的商品並返回,甚至是沒有需要的商品也會立即返回。

阻塞IO會使得執行緒將大量的時間浪費在等待IO上,這是非常不划算的,但是這種阻塞可以在資料可用時立即獲取並處理資料,而非阻塞IO則必須通過重複的呼叫來獲取全部資料。

Java NIO 使用Selector實現單執行緒管理多個Channel,通過 select 呼叫,可以獲取已經準備好的Channel並進行相應的處理。

Java IO 工作流程

由於Java IO是阻塞的,所以當面對多個流的讀寫時需要多個執行緒處理。例如在網路IO中,Server端使用一個執行緒監聽一個埠,一旦某個連線被accept,建立新的執行緒來處理新建立的連線。
Java IO

其中 read/write 是阻塞的。

Java NIO 工作流程

Java NIO 提供 Selector 實現單個執行緒管理多個channel的功能。
Java NIO

其中select 呼叫可能是阻塞的,也可以是非阻塞的。但是read/write是非阻塞的!