Java NIO:IO與NIO的區別

來源:互聯網
上載者:User

標籤:title   寫入   返回   email   from   非阻塞   操作   存在   JD   

https://www.cnblogs.com/xiaoxi/p/6576588.html

 

一、概念

     NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但實現方式不同,NIO主要用到的是塊,所以NIO的效率要比IO高很多。在Java API中提供了兩套NIO,一套是針對標準輸入輸出NIO,另一套就是網路編程NIO。

二、NIO和IO的主要區別

下表總結了Java IO和NIO之間的主要區別:

IO NIO
面向流 面向緩衝
阻塞IO 非阻塞IO
無 選取器

 

 

 

 

1、面向流與面向緩衝

     Java IO和NIO之間第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。 Java IO面向流意味著每次從流中讀一個或多個位元組,直至讀取所有位元組,它們沒有被緩衝在任何地方。此外,它不能前後移動流中的資料。如果需要前後移動從流中讀取的資料,需要先將它緩衝到一個緩衝區。 Java NIO的緩衝導向方法略有不同。資料讀取到一個它稍後處理的緩衝區,需要時可在緩衝區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩衝區中包含所有您需要處理的資料。而且,需確保當更多的資料讀入緩衝區時,不要覆蓋緩衝區裡尚未處理的資料。

2、阻塞與非阻塞IO

     Java IO的各種流是阻塞的。這意味著,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些資料被讀取,或資料完全寫入。該線程在此期間不能再幹任何事情了。Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可用時,就什麼都不會擷取,而不是保持線程阻塞,所以直至資料變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此。一個線程請求寫入一些資料到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閑時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。

3、選取器(Selectors)

     Java NIO的選取器允許一個單獨的線程來監視多個輸入通道,你可以註冊多個通道使用一個選取器,然後使用一個單獨的線程來“選擇”通道:這些通道裡已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。

三、NIO和IO如何影響應用程式的設計

無論您選擇IO或NIO工具箱,可能會影響您應用程式設計的以下幾個方面:

1.對NIO或IO類的API調用。
2.資料處理。
3.用來處理資料的線程數。

1、API調用

當然,使用NIO的API調用時看起來與使用IO時有所不同,但這並不意外,因為並不是僅從一個InputStream逐位元組讀取,而是資料必須先讀入緩衝區再處理。

2、資料處理

使用純粹的NIO設計相較IO設計,資料處理也受到影響。

在IO設計中,我們從InputStream或 Reader逐位元組讀取資料。假設你正在處理一基於行的文本資料流,例如:

Name: Anna Age: 25Email: [email protected] Phone: 1234567890 

該文本行的流可以這樣處理:

InputStream input = ... ; // get the InputStream from the client socket   BufferedReader reader = new BufferedReader(new InputStreamReader(input));   String nameLine   = reader.readLine(); String ageLine    = reader.readLine(); String emailLine  = reader.readLine(); String phoneLine  = reader.readLine(); 

     請注意處理狀態由程式執行多久決定。換句話說,一旦reader.readLine()方法返回,你就知道肯定文本行就已讀完, readline()阻塞直到整行讀完,這就是原因。你也知道此行包含名稱;同樣,第二個readline()調用返回的時候,你知道這行包含年齡等。 正如你可以看到,該處理常式僅在有新資料讀入時運行,並知道每步的資料是什麼。一旦正在啟動並執行線程已處理過讀入的某些資料,該線程不會再回退資料(大多如此)。也說明了這條原則:

而一個NIO的實現會有所不同,下面是一個簡單的例子:

ByteBuffer buffer = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buffer); 

注意第二行,從通道讀取位元組到ByteBuffer。當這個方法調用返回時,你不知道你所需的所有資料是否在緩衝區內。你所知道的是,該緩衝區包含一些位元組,這使得處理有點困難。假設第一次 read(buffer)調用後,讀入緩衝區的資料只有半行,例如,“Name:An”,你能處理資料嗎?顯然不能,需要等待,直到整行資料讀入緩衝,在此之前,對資料的任何處理毫無意義。所以,你怎麼知道是否該緩衝區包含足夠的資料可以處理呢?好了,你不知道。發現的方法只能查看緩衝區中的資料。其結果是,在你知道所有資料都在緩衝區裡之前,你必須檢查幾次緩衝區的資料。這不僅效率低下,而且可以使程式設計方案雜亂不堪。例如:

ByteBuffer buffer = ByteBuffer.allocate(48);   int bytesRead = inChannel.read(buffer);   while(! bufferFull(bytesRead) ) {          bytesRead = inChannel.read(buffer);   } 

bufferFull()方法必須跟蹤有多少資料讀入緩衝區,並返回真或假,這取決於緩衝區是否已滿。換句話說,如果緩衝區準備好被處理,那麼表示緩衝區滿了。

bufferFull()方法掃描緩衝區,但必須保持在bufferFull()方法被調用之前狀態相同。如果沒有,下一個讀入緩衝區的資料可能無法讀到正確的位置。這是不可能的,但卻是需要注意的又一問題。

如果緩衝區已滿,它可以被處理。如果它不滿,並且在你的實際案例中有意義,你或許能處理其中的部分資料。但是許多情況下並非如此。展示了“緩衝區資料迴圈就緒”:

四、總結

NIO可讓您只使用一個(或幾個)單線程管理多個通道(網路連接或檔案),但付出的代價是解析資料可能會比從一個阻塞流中讀取資料更複雜。

如果需要管理同時開啟的成千上萬個串連,這些串連每次只是發送少量的資料,例如聊天伺服器,實現NIO的伺服器可能是一個優勢。同樣,如果你需要維持許多開啟的串連到其他電腦上,如P2P網路中,使用一個單獨的線程來管理你所有出站串連,可能是一個優勢。一個線程多個串連的設計方案如所示:

Java NIO: 單線程管理多個串連

如果你有少量的串連使用非常高的頻寬,一次發送大量的資料,也許典型的IO伺服器實現可能非常契合。說明了一個典型的IO伺服器設計:

Java IO: 一個典型的IO伺服器設計- 一個串連通過一個線程處理.

Java NIO:IO與NIO的區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.