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
Channel
Channel的實現: (涵蓋了UDP 和 TCP 網路IO,以及檔案IO)
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
讀資料:
- int bytesRead = inChannel.read(buf);
寫資料:
- int bytesWritten = inChannel.write(buf);
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()方法。這個方法會一直阻塞到某個註冊的通道有事件就緒。一旦這個方法返回,執行緒就可以處理這些事件,事件的例子有如新連線進來,資料接收等。使用
- 建立:Selector selector = Selector.open();
- 註冊通道:
- 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的判斷
- channel.configureBlocking(false);
- 使用:
- select():阻塞到至少有一個通道在你註冊的事件上就緒了
- selectNow():不會阻塞,不管什麼通道就緒都立刻返回
- selectedKeys():訪問“已選擇鍵集(selected key set)”中的就緒通道
- close():使用完selector需要用其close()方法會關閉該Selector,且使註冊到該Selector上的所有SelectionKey例項無效
- Set selectedKeys = selector.selectedKeys();
- Iterator keyIterator = selectedKeys.iterator();
- while(keyIterator.hasNext()) {
- SelectionKey key = keyIterator.next();
- if(key.isAcceptable()) {
- // a connection was accepted by a ServerSocketChannel.
- } else if (key.isConnectable()) {
- // a connection was established with a remote server.
- } else if (key.isReadable()) {
- // a channel is ready for reading
- } else if (key.isWritable()) {
- // a channel is ready for writing
- }
- keyIterator.remove();//注意這裡必須手動remove;表明該selectkey我已經處理過了;
- }
Java測試關鍵程式碼
- RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
- FileChannel inChannel = aFile.getChannel(); //從一個InputStream outputstream中獲取channel
- //create buffer with capacity of 48 bytes
- ByteBuffer buf = ByteBuffer.allocate(48);
- int bytesRead = inChannel.read(buf); //read into buffer.
- while (bytesRead != -1) {
- buf.flip(); //make buffer ready for read
- while(buf.hasRemaining()){
- System.out.print((char) buf.get()); // read 1 byte at a time
- }
- buf.clear(); //make buffer ready for writing
- bytesRead = inChannel.read(buf);
- }
- aFile.close();
檔案通道
- RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
- FileChannel inChannel = aFile.getChannel();
- ByteBuffer buf = ByteBuffer.allocate(48);
- int bytesRead = inChannel.read(buf);
- String newData = "New String to write to file..." + System.currentTimeMillis();
- ByteBuffer buf = ByteBuffer.allocate(48);
- buf.clear();
- buf.put(newData.getBytes());
- buf.flip();
- while(buf.hasRemaining()) {
- channel.write(buf);
- }
Socket 通道
- SocketChannel socketChannel = SocketChannel.open();
- socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
- ByteBuffer buf = ByteBuffer.allocate(48);
- int bytesRead = socketChannel.read(buf);
- String newData = "New String to write to file..." + System.currentTimeMillis();
- ByteBuffer buf = ByteBuffer.allocate(48);
- buf.clear();
- buf.put(newData.getBytes());
- buf.flip();
- while(buf.hasRemaining()) {
- socketChannel.write(buf);
- }
ServerSocket 通道
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.socket().bind(new InetSocketAddress(9999));
- while(true){
- SocketChannel socketChannel =
- serverSocketChannel.accept();
- //do something with socketChannel...
- }
Datagram 通道(channel的讀寫操作與前面的有差異)
- DatagramChannel channel = DatagramChannel.open();
- channel.socket().bind(new InetSocketAddress(9999));
- ByteBuffer buf = ByteBuffer.allocate(48);
- buf.clear();
- channel.receive(buf);
- //receive()方法會將接收到的資料包內容複製到指定的Buffer. 如果Buffer容不下收到的資料,多出的資料將被丟棄。
- String newData = "New String to write to file..." + System.currentTimeMillis();
- ByteBuffer buf = ByteBuffer.allocate(48);
- buf.clear();
- buf.put(newData.getBytes());
- buf.flip();
- int bytesSent = channel.send(buf, new InetSocketAddress("jenkov.com", 80));
相關推薦
Java NIO 與 IO之間的區別
概述 Java NIO提供了與標準IO不同的IO工作方式: Channels and Buffers(通道和緩衝區):標準的IO基於位元組流和字元流進行操作的,而NIO是基於通道(Channel)和緩
Java NIO與IO的區別和比較
選擇器 獲取 如果 得到 提供服務 單獨 每次 取數 details 現代的酒店服務方式跟傳統的區別有兩個:1、增加了一個角色,要有一個專門負責收集客人需求的人。NIO裏對應的就是Selector。2、由阻塞服務方式改為非阻塞服務了,客人吃著的時候服務員不用一直侯在客人旁邊
Java NIO與IO的區別和比較,NIO與IO執行緒池效能比較
傳統的socket IO中,需要為每個連線建立一個執行緒,當併發的連線數量非常巨大時,執行緒所佔用的棧記憶體和CPU執行緒切換的開銷將非常巨大。使用NIO,不再需要為每個執行緒建立單獨的執行緒,可以用一個含有限數量執行緒的執行緒池,甚至一個執行緒來為任意數量的連線服務。由於執行緒數量小於連線數量,所
Java NIO與IO的區別
Java.nio 俗稱 New IO (從1.4開始),全稱是Java Non-blocking IO,即非阻塞的IO,為所有的原始型別(boolean型別除外)提供快取支持的資料容器,使用它可以提供非阻塞式的高伸縮性網路IO。 NIO與IO的區別: 1.標準的IO的操作都
java NIO NIO與IO的區別
一、概念 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 NIO與IO
作者:Jakob Jenkov 譯者:郭蕾 校對:方騰飛 當學習了Java NIO和IO的API後,一個問題馬上湧入腦海: 我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影響您的程式碼設計。 Java
NIO與IO的區別
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 NIO與IO
當學習了Java NIO和IO的API後,一個問題馬上湧入腦海: 我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影響您的程式碼設計。 Java NIO和IO的主要區別 下表總結了Java NIO和
Java NIO:IO與NIO的區別
文件 目的 讀取數據 簡單的 什麽 毫無 log 再處理 很多 一、概念 NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但實現方式不同,NIO主要用到的是塊,所以NIO的效率要比IO高很多。在Java API中提供了
[JAVA學習筆記-68]NIO與AIO的區別
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-記憶體對映檔案MappedByteBuffer與zerocopy
在傳統的檔案IO操作中,我們都是呼叫作業系統提供的底層標準IO系統呼叫函式read()、write() ,此時呼叫此函式的程序(在JAVA中即java程序)由當前的使用者態切換到核心態,然後OS的核心程式碼負責將相應的檔案資料讀取到核心的IO緩衝區,然後再把資料
String、StringBuffer與StringBuilder之間區別 .RP
什麽 方式 tr1 abcd 為什麽 mes strong 速度 一點 最近學習到StringBuffer,心中有好些疑問,搜索了一些關於String,StringBuffer,StringBuilder的東西,現在整理一下。 關於這三個類在字符串處理中的位置不言而喻,
String、StringBuffer與StringBuilder之間區別
安全 .com 學習 ron img build tro ges 變量 大家在最初結束String字符串的時候,都會被教做認為String是不可變的字符串常量,是不可改變的常量。但是我們看下面的一個列子: 為什麽會發生這種情況呢?難道最開始我們學習的就是錯誤的?
Java nio和io
處理程序 lines shell 都在 cto 付出 機制 如何 線程阻塞 當學習了Java NIO和IO的API後,一個問題馬上湧入腦海: 我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影響您
java-----instanceof與getClass的區別
stat boa strong clipboard oid pla class test 通過 在比較一個類是否和另一個類屬於同一個類實例的時候,我們通常可以采用instanceof和getClass兩種方法通過兩者是否相等來判斷,但是兩者在判斷上面是有差別的,下面從代碼中
java---Hashset與Hashmap的區別
first 一個 有一個 成功 5% syn 映射 我們 equals HashMap和HashSet的區別是Java面試中最常被問到的問題。如果沒有涉及到Collection框架以及多線程的面試,可以說是不完整。而Collection框架的問題不涉及到HashSet和Ha
自己(轉)String、StringBuffer與StringBuilder之間區別
理解 疑問 多線程 blog gpo string類 body 對象 就是 最近學習到StringBuffer,心中有好些疑問,搜索了一些關於String,StringBuffer,StringBuilder的東西,現在整理一下。 關於這三個類在字符串處理中的位置不言
Java FileInputStream與FileReader的區別
取數據 內存 字符編碼 緩存 () print out main 阻塞 在解釋Java中FileInputStream和FileReader的具體區別之前,我想講述一下Java中InputStream和Reader的根本差異,以及分別什麽時候使用InputStream和Re