1. 程式人生 > >Java NIO 與 IO之間的區別

Java NIO 與 IO之間的區別

概述

Java NIO提供了與標準IO不同的IO工作方式: 
  • Channels and Buffers(通道和緩衝區):標準的IO基於位元組流和字元流進行操作的,而NIO是基於通道(Channel)和緩衝區(Buffer)進行操作,資料總是從通道讀取到緩衝區中,或者從緩衝區寫入到通道中。
  • Asynchronous IO(非同步IO):Java NIO可以讓你非同步的使用IO,例如:當執行緒從通道讀取資料到緩衝區時,執行緒還是可以進行其他事情。當資料被寫入到緩衝區時,執行緒可以繼續處理它。從緩衝區寫入通道也類似。
  • Selectors(選擇器):Java NIO引入了選擇器的概念,選擇器用於監聽多個通道的事件(比如:連線開啟,資料到達)。因此,單個的執行緒可以監聽多個數據通道。

使用場景

NIO

  • 優勢在於一個執行緒管理多個通道;但是資料的處理將會變得複雜;
  • 如果需要管理同時開啟的成千上萬個連線,這些連線每次只是傳送少量的資料,採用這種;

傳統的IO

  • 適用於一個執行緒管理一個通道的情況;因為其中的流資料的讀取是阻塞的;
  • 如果需要管理同時開啟不太多的連線,這些連線會發送大量的資料;

NIO vs IO區別

NIO vs IO之間的理念上面的區別(NIO將阻塞交給了後臺執行緒執行)
  • IO是面向流的,NIO是面向緩衝區的
    • Java IO面向流意味著每次從流中讀一個或多個位元組,直至讀取所有位元組,它們沒有被快取在任何地方;
    • NIO則能前後移動流中的資料,因為是面向緩衝區的
  • IO流是阻塞的,NIO流是不阻塞的
    • Java IO的各種流是阻塞的。這意味著,當一個執行緒呼叫read() 或 write()時,該執行緒被阻塞,直到有一些資料被讀取,或資料完全寫入。該執行緒在此期間不能再幹任何事情了
    • Java NIO的非阻塞模式,使一個執行緒從某通道傳送請求讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可用時,就什麼都不會獲取NIO可讓您只使用一個(或幾個)單執行緒管理多個通道(網路連線或檔案),但付出的代價是解析資料可能會比從一個阻塞流中讀取資料更復雜。 
    • 非阻塞寫也是如此。一個執行緒請求寫入一些資料到某通道,但不需要等待它完全寫入,這個執行緒同時可以去做別的事情。
  • 選擇器
    • Java NIO的選擇器允許一個單獨的執行緒來監視多個輸入通道,你可以註冊多個通道使用一個選擇器,然後使用一個單獨的執行緒來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的執行緒很容易來管理多個通道。 

Java NIO 由以下幾個核心部分組成: 


  • Channels
  • Buffers
  • Selectors
基本上,所有的 IO 在NIO 中都從一個Channel 開始。Channel 有點象流。 資料可以從Channel讀到Buffer中,也可以從Buffer 寫到Channel中。這裡有個圖示: 

Channel

Channel的實現: (涵蓋了UDP 和 TCP 網路IO,以及檔案IO)

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

讀資料:

  • int bytesRead = inChannel.read(buf);

寫資料:

  • int bytesWritten = inChannel.write(buf);  
還有部分的使用,如配置Channel為阻塞或者非阻塞模式,以及如何註冊到Selector上面去,參考Selector部分;

Buffer

Buffer實現: (byte, char、short, int, long, float, double )

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

Buffer使用

讀資料
  • flip()方法
    • 將Buffer從寫模式切換到讀模式
    • 呼叫flip()方法會將position設回0,並將limit設定成之前position的值。
    • buf.flip();
  •  (char) buf.get()
    • 讀取資料
  • Buffer.rewind()
    • 將position設回0,所以你可以重讀Buffer中的所有資料
    • limit保持不變,仍然表示能從Buffer中讀取多少個元素(byte、char等)
  • Buffer.mark()方法,可以標記Buffer中的一個特定position。之後可以通過呼叫
  • Buffer.reset()方法,恢復到Buffer.mark()標記時的position
  • 一旦讀完了所有的資料,就需要清空緩衝區,讓它可以再次被寫入。
  • clear()方法會:
    • 清空整個緩衝區。
    • position將被設回0,limit被設定成 capacity的值
  • compact()方法:
    • 只會清除已經讀過的資料;任何未讀的資料都被移到緩衝區的起始處,新寫入的資料將放到緩衝區未讀資料的後面。
    • 將position設到最後一個未讀元素正後面,limit被設定成 capacity的值
寫資料
  • buf.put(127);  

Buffer的三個屬性

  • capacity:含義與模式無關;Buffer的一個固定的大小值;Buffer滿了需要將其清空才能再寫;
    • ByteBuffer.allocate(48);該buffer的capacity為48byte
    • CharBuffer.allocate(1024);該buffer的capacity為1024個char 
  • position:含義取決於Buffer處在讀模式還是寫模式(初始值為0,寫或者讀操作的當前位置)
    • 寫資料時,初始的position值為0;其值最大可為capacity-1
    • 將Buffer從寫模式切換到讀模式,position會被重置為0
  • limit:含義取決於Buffer處在讀模式還是寫模式(寫limit=capacity;讀limit等於最多可以讀取到的資料)
    • 寫模式下,limit等於Buffer的capacity
    • 切換Buffer到讀模式時, limit表示你最多能讀到多少資料;

Selector

概述

    Selector允許單執行緒處理多個 Channel。如果你的應用打開了多個連線(通道),但每個連線的流量都很低,使用Selector就會很方便。例如,在一個聊天伺服器中。     要使用Selector,得向Selector註冊Channel,然後呼叫它的select()方法。這個方法會一直阻塞到某個註冊的通道有事件就緒。一旦這個方法返回,執行緒就可以處理這些事件,事件的例子有如新連線進來,資料接收等。

使用

  1. 建立:Selector selector = Selector.open();  
  2. 註冊通道:
    • channel.configureBlocking(false);  
      • //與Selector一起使用時,Channel必須處於非阻塞模式
      • //這意味著不能將FileChannel與Selector一起使用,因為FileChannel不能切換到非阻塞模式(而套接字通道都可以)
    • SelectionKey key = channel.register(selector, Selectionkey.OP_READ); 
      • //第二個引數表明Selector監聽Channel時對什麼事件感興趣
      • //SelectionKey.OP_CONNECT  SelectionKey.OP_ACCEPT  SelectionKey.OP_READ SelectionKey.OP_WRITE
      • //可以用或操作符將多個興趣組合一起
    • SelectionKey
      • 包含了interest集合 、ready集合 、Channel 、Selector 、附加的物件(可選)
      • int interestSet = key.interestOps();可以進行類似interestSet & SelectionKey.OP_CONNECT的判斷
  3. 使用:
    • select():阻塞到至少有一個通道在你註冊的事件上就緒了
    • selectNow():不會阻塞,不管什麼通道就緒都立刻返回
    • selectedKeys():訪問“已選擇鍵集(selected key set)”中的就緒通道
    • close():使用完selector需要用其close()方法會關閉該Selector,且使註冊到該Selector上的所有SelectionKey例項無效
  1. Set selectedKeys = selector.selectedKeys();  
  2. Iterator keyIterator = selectedKeys.iterator();  
  3. while(keyIterator.hasNext()) {  
  4.     SelectionKey key = keyIterator.next();  
  5.     if(key.isAcceptable()) {  
  6.         // a connection was accepted by a ServerSocketChannel.  
  7.     } else if (key.isConnectable()) {  
  8.         // a connection was established with a remote server.  
  9.     } else if (key.isReadable()) {  
  10.         // a channel is ready for reading  
  11.     } else if (key.isWritable()) {  
  12.         // a channel is ready for writing  
  13.     } 
  14.     keyIterator.remove();//注意這裡必須手動remove;表明該selectkey我已經處理過了;
  15. }

Java測試關鍵程式碼

  1. RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt""rw");  
  2. FileChannel inChannel = aFile.getChannel();  //從一個InputStream outputstream中獲取channel
  3. //create buffer with capacity of 48 bytes  
  4. ByteBuffer buf = ByteBuffer.allocate(48);  
  5. int bytesRead = inChannel.read(buf); //read into buffer.  
  6. while (bytesRead != -1) {  
  7.   buf.flip();  //make buffer ready for read  
  8.   while(buf.hasRemaining()){  
  9.       System.out.print((char) buf.get()); // read 1 byte at a time  
  10.   }  
  11.   buf.clear(); //make buffer ready for writing  
  12.   bytesRead = inChannel.read(buf);  
  13. }  
  14. aFile.close();  

檔案通道

  1. RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt""rw");  
  2. FileChannel inChannel = aFile.getChannel();  
讀資料
  1. ByteBuffer buf = ByteBuffer.allocate(48);  
  2. int bytesRead = inChannel.read(buf);  
寫資料
  1. String newData = "New String to write to file..." + System.currentTimeMillis();  
  2. ByteBuffer buf = ByteBuffer.allocate(48);  
  3. buf.clear();  
  4. buf.put(newData.getBytes());  
  5. buf.flip();  
  6. while(buf.hasRemaining()) {  
  7.     channel.write(buf);  

Socket 通道

  1. SocketChannel socketChannel = SocketChannel.open();  
  2. socketChannel.connect(new InetSocketAddress("http://jenkov.com"80));  
讀資料
  1. ByteBuffer buf = ByteBuffer.allocate(48);  
  2. int bytesRead = socketChannel.read(buf);  
寫資料
  1. String newData = "New String to write to file..." + System.currentTimeMillis();  
  2. ByteBuffer buf = ByteBuffer.allocate(48);  
  3. buf.clear();  
  4. buf.put(newData.getBytes());  
  5. buf.flip();  
  6. while(buf.hasRemaining()) {  
  7.     socketChannel.write(buf);  
  8. }  

ServerSocket 通道

  1. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  
  2. serverSocketChannel.socket().bind(new InetSocketAddress(9999));  
  3. while(true){  
  4.     SocketChannel socketChannel =  
  5.             serverSocketChannel.accept();  
  6.     //do something with socketChannel...  

Datagram 通道(channel的讀寫操作與前面的有差異)

  1. DatagramChannel channel = DatagramChannel.open();  
  2. channel.socket().bind(new InetSocketAddress(9999));  
讀資料
  1. ByteBuffer buf = ByteBuffer.allocate(48);  
  2. buf.clear();  
  3. channel.receive(buf);
  4. //receive()方法會將接收到的資料包內容複製到指定的Buffer. 如果Buffer容不下收到的資料,多出的資料將被丟棄。 
寫資料
  1. String newData = "New String to write to file..." + System.currentTimeMillis();  
  2. ByteBuffer buf = ByteBuffer.allocate(48);  
  3. buf.clear();  
  4. buf.put(newData.getBytes());  
  5. buf.flip();  
  6. int bytesSent = channel.send(buf, new InetSocketAddress("jenkov.com"80));  

相關推薦

Java NIO IO之間區別

概述 Java NIO提供了與標準IO不同的IO工作方式: Channels and Buffers(通道和緩衝區):標準的IO基於位元組流和字元流進行操作的,而NIO是基於通道(Channel)和緩

Java NIOIO區別和比較

選擇器 獲取 如果 得到 提供服務 單獨 每次 取數 details 現代的酒店服務方式跟傳統的區別有兩個:1、增加了一個角色,要有一個專門負責收集客人需求的人。NIO裏對應的就是Selector。2、由阻塞服務方式改為非阻塞服務了,客人吃著的時候服務員不用一直侯在客人旁邊

Java NIOIO區別和比較,NIOIO執行緒池效能比較

     傳統的socket IO中,需要為每個連線建立一個執行緒,當併發的連線數量非常巨大時,執行緒所佔用的棧記憶體和CPU執行緒切換的開銷將非常巨大。使用NIO,不再需要為每個執行緒建立單獨的執行緒,可以用一個含有限數量執行緒的執行緒池,甚至一個執行緒來為任意數量的連線服務。由於執行緒數量小於連線數量,所

Java NIOIO區別

Java.nio 俗稱 New IO (從1.4開始),全稱是Java Non-blocking IO,即非阻塞的IO,為所有的原始型別(boolean型別除外)提供快取支持的資料容器,使用它可以提供非阻塞式的高伸縮性網路IO。 NIO與IO的區別: 1.標準的IO的操作都

java NIO NIOIO區別

一、概念      NIO即New IO,但是我認為理解為no-blocking IO(非阻塞IO)更貼切,這個庫是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但實現方式不同,NIO主要用到的是塊,所以NIO的效率要比IO高很多。在Java

Java NIO系列教程(十二) Java NIO IO

Java NIO系列教程(十二) Java NIO 與 IO 當學習了 Java NIO 和 IO 的 API 後,一個問題馬上湧入腦海: 我應該何時使用 IO,何時使用 NIO 呢?在本文中,我會盡量清晰地解析 Java NIO 和 IO 的差異、它們的使用場景,以及它們如何影響您的程式碼設計。 下表

Java NIO系列教程(十二) Java NIOIO

作者:Jakob Jenkov   譯者:郭蕾    校對:方騰飛 當學習了Java NIO和IO的API後,一個問題馬上湧入腦海: 我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影響您的程式碼設計。 Java

NIOIO區別

JAVA NIO vs IO 當我們學習了Java NIO和IO後,我們很快就會思考一個問題: 什麼時候應該使用IO,什麼時候我應該使用NIO 在下文中我會嘗試用例子闡述java NIO 和IO的區別,以及它們對你的設計會有什麼影響 Java NIO和IO的主要區別 IO

Java NIO IO

作者:Jakob Jenkov   譯者:郭蕾    校對:方騰飛 當學習了Java NIO和IO的API後,一個問題馬上湧入腦海: 我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影

Java NIO系列教程(12)Java NIOIO

當學習了Java NIO和IO的API後,一個問題馬上湧入腦海: 我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影響您的程式碼設計。 Java NIO和IO的主要區別 下表總結了Java NIO和

Java NIOIONIO區別

文件 目的 讀取數據 簡單的 什麽 毫無 log 再處理 很多 一、概念 NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但實現方式不同,NIO主要用到的是塊,所以NIO的效率要比IO高很多。在Java API中提供了

[JAVA學習筆記-68]NIOAIO的區別

    non-blocking IO vs async IO and implementation in JavaYou understand the terms correctly. As noted, "non-blocking async IO" would be

Java NIO 檔案IO-記憶體對映檔案MappedByteBufferzerocopy

在傳統的檔案IO操作中,我們都是呼叫作業系統提供的底層標準IO系統呼叫函式read()、write() ,此時呼叫此函式的程序(在JAVA中即java程序)由當前的使用者態切換到核心態,然後OS的核心程式碼負責將相應的檔案資料讀取到核心的IO緩衝區,然後再把資料

String、StringBufferStringBuilder之間區別 .RP

什麽 方式 tr1 abcd 為什麽 mes strong 速度 一點   最近學習到StringBuffer,心中有好些疑問,搜索了一些關於String,StringBuffer,StringBuilder的東西,現在整理一下。 關於這三個類在字符串處理中的位置不言而喻,

String、StringBufferStringBuilder之間區別

安全 .com 學習 ron img build tro ges 變量   大家在最初結束String字符串的時候,都會被教做認為String是不可變的字符串常量,是不可改變的常量。但是我們看下面的一個列子:   為什麽會發生這種情況呢?難道最開始我們學習的就是錯誤的?

Java nioio

處理程序 lines shell 都在 cto 付出 機制 如何 線程阻塞 當學習了Java NIO和IO的API後,一個問題馬上湧入腦海: 我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影響您

java-----instanceofgetClass的區別

stat boa strong clipboard oid pla class test 通過 在比較一個類是否和另一個類屬於同一個類實例的時候,我們通常可以采用instanceof和getClass兩種方法通過兩者是否相等來判斷,但是兩者在判斷上面是有差別的,下面從代碼中

java---HashsetHashmap的區別

first 一個 有一個 成功 5% syn 映射 我們 equals HashMap和HashSet的區別是Java面試中最常被問到的問題。如果沒有涉及到Collection框架以及多線程的面試,可以說是不完整。而Collection框架的問題不涉及到HashSet和Ha

自己(轉)String、StringBufferStringBuilder之間區別

理解 疑問 多線程 blog gpo string類 body 對象 就是   最近學習到StringBuffer,心中有好些疑問,搜索了一些關於String,StringBuffer,StringBuilder的東西,現在整理一下。 關於這三個類在字符串處理中的位置不言

Java FileInputStreamFileReader的區別

取數據 內存 字符編碼 緩存 () print out main 阻塞 在解釋Java中FileInputStream和FileReader的具體區別之前,我想講述一下Java中InputStream和Reader的根本差異,以及分別什麽時候使用InputStream和Re