說說java NIO的一些個人總結__nio

來源:互聯網
上載者:User
首先瞭解下所謂的java nio是個什麼東西。
IO是靠字元或位元組進行傳輸,比較慢。 而NIO是靠塊, 也就相當於一個Buffer, 一塊一塊
的傳輸, 速度較快
。 同時加入了多線程
的控制, 一個NIO流可以同時傳輸多個塊等, 也就是所謂的非同步傳輸
; 
傳統
的並髮型
伺服器設計是利用阻塞型網路I/O
以多線程的模式(一個SOCKET連結,服務端就啟動一個線程接受服務
)來實現的,然而由
於系統常常在進行網路讀寫時處於阻塞狀態,會大大影響系統的效能
;自Java1. 4 開始引入
了NIO(新I/O) API,通過使用非阻塞型
I/O
,實現流暢的網路讀寫操作,為開發高效能並發
型伺服器程式提供了一個很好的解決方案。這就是java nio 
首先來看下傳統的阻塞型網路 I/O的不足 Java 平台傳統的I/O 系統都是基於Byte(位元組)和Stream(資料流)的,相應的I/O 操作都是阻塞型的

所以伺服器程式也採用阻塞型I/O
進行資料的讀、寫操作。本文以TCP長串連模式來討論並髮型伺服器的相關設計,為了實現伺服器程式的並發性要求,系統由一個單獨的主線程來監聽使用者發起的
串連請求,一直處於阻塞狀態;當有使用者串連請求到來時,程式都會啟一個新的線程來統一處理使用者資料的讀、寫操作。
這種模式的優點是簡單、實用、易管理;然而缺點也是顯而易見的:由於是為每一個用戶端分配一個線程來處理輸入、輸出資料,其線程與客戶機的比例近似為1:1
,隨著線程數量的不斷增加,伺服器啟動了大量的並發線程,會大大加大系統對線程的管理開銷
,這將成為輸送量瓶頸的主要原因
;其次由於底層的I/O 操作採用的同步模式,I/O 操作的阻塞管理粒度是以服務於請求的線程為單位的,有可能大量的線程會閑置,處於盲等狀態,造成I/O資源使用率不高,影響整個系統的效能。
對於並髮型伺服器,系統用在阻塞型I/O 等待和線程間切換的時間遠遠多於
CPU 在內
存中處理資料的時間,因此傳統的阻塞型I/O 已經成為制約系統效能的瓶頸。Java1.4 版本
後推出的NIO 工具包,提供了非阻塞型I/O 的非同步輸入輸出
機制
,為提高系統的效能提供
了可實現的基礎機制。 
NIO 包及工作原理
針對傳統I/O 工作模式的不足,NIO 工具包提出了基於Buffer(緩衝區)、Channel(通
道)、Selector(選取器)的新模式;Selector(選取器)、可選擇的Channel(通道)和
SelectionKey(選擇鍵)配合起來使用,可以實現並發的非阻塞型I/O 能力。 
NIO 工具包的成員

Buffer(緩衝器)


1.   基本 概念

IO 是主存和外部裝置 ( 硬碟、終端和網路等 ) 拷貝資料的過程。 IO 是作業系統的底層功能實現,底層通過 I/O 指令進行完成。

所有語言運行時系統提供執行 I/O 較進階別的工具。 (c 的 printf scanf,Java 的物件導向封裝 )

2.    Java 標準 io 回顧

Java 標準 IO 類庫是 io 物件導向的一種抽象。基於本地方法的底層實現,我們無須關注底層實現。 InputStream\OutputStream( 位元組流 ):一次傳送一個位元組。 Reader\Writer( 字元流 ) :一次一個字元。

3.    nio 簡介

nio 是 Java New IO 的簡稱,在 jdk1.4 裡提供的新 api 。 Sun 官方標榜的特性如下:

–     為所有的原始類型提供 (Buffer) 緩衝支援。

–     字元集編碼解碼解決方案。

–     Channel :一個新的原始 I/O 抽象。

–     支援鎖和記憶體對應檔的檔案提供者。

–     提供多路 (non-bloking) 非阻塞式的高伸縮性網路 I/O 。

本文將圍繞這幾個特性進行學習和介紹。

4.   Buffer&Chanel

Channel 和 buffer 是 NIO 是兩個最基本的資料類型抽象。

Buffer:

–        是一塊連續的記憶體塊。

–        是 NIO 資料讀或寫的中轉地。

Channel:

–        資料的源頭或者資料的目的地

–        用於向 buffer 提供資料或者讀取 buffer 資料 ,buffer 對象的唯一介面。

–         非同步 I/O 支援


圖1:channel和buffer關係
 

 

例子 1:CopyFile.java:

  Java代碼    package sample;      import java.io.FileInputStream;   import java.io.FileOutputStream;   import java.nio.ByteBuffer;   import java.nio.channels.FileChannel;      public class CopyFile {       public static void main(String[] args) throws Exception {           String infile = "C:\\copy.sql";           String outfile = "C:\\copy.txt";           // 擷取源檔案和目標檔案的輸入輸出資料流           FileInputStream fin = new FileInputStream(infile);           FileOutputStream fout = new FileOutputStream(outfile);           // 擷取輸入輸出通道           FileChannel fcin = fin.getChannel();           FileChannel fcout = fout.getChannel();           // 建立緩衝區           ByteBuffer buffer = ByteBuffer.allocate(1024);           while (true) {               // clear方法重設緩衝區,使它可以接受讀入的資料               buffer.clear();               // 從輸入通道中將資料讀到緩衝區               int r = fcin.read(buffer);               // read方法返回讀取的位元組數,可能為零,如果該通道已到達流的末尾,則返回-1               if (r == -1) {                   break;               }               // flip方法讓緩衝區可以將新讀入的資料寫入另一個通道               buffer.flip();               // 從輸出通道中將資料寫入緩衝區               fcout.write(buffer);           }       }   }  

 

 

其中 buffer 內部結構如下 ( 下圖拷貝自資料 ):


圖2:buffer內部結構 

一個 buffer 主要由 position,limit,capacity 三個變數來控制讀寫的過程。此三個變數的含義見如下表格:

參數

寫入模式   

讀模式

position

當前寫入的單位元據數量。

當前讀取的單位元據位置。

limit

代表最多能寫多少單位元據和容量是一樣的。

代表最多能讀多少單位元據,和之前寫入的單位元據量一致。

capacity

buffer 容量

buffer 容量

Buffer 常見方法:

flip(): 寫入模式轉換成讀模式

rewind() :將 position 重設為 0 ,一般用於重複讀。

clear() :清空 buffer ,準備再次被寫入 (position 變成 0 , limit 變成 capacity) 。

compact(): 將未讀取的資料拷貝到 buffer 的頭部位。

mark() 、 reset():mark 可以標記一個位置, reset 可以重設到該位置。

Buffer 常見類型: ByteBuffer 、 MappedByteBuffer 、 CharBuffer 、 DoubleBuffer 、 FloatBuffer 、 IntBuffer 、 LongBuffer 、ShortBuffer 。

channel 常見類型 :FileChannel 、 DatagramChannel(UDP) 、 SocketChannel(TCP) 、 ServerSocketChannel(TCP)

在本機上面做了個簡單的效能測試。我的筆記本效能一般。 ( 具體代碼可以見附件。見 nio.sample.filecopy 包下面的例子 ) 以下是參考資料:

–        情境 1 : Copy 一個 370M 的檔案

–        情境 2: 三個線程同時拷貝,每個線程拷貝一個 370M 檔案

 

情境

FileInputStream+

FileOutputStream

FileInputStream+

BufferedInputStream+

FileOutputStream

ByteBuffer+

FileChannel

MappedByteBuffer

+FileChannel

情境一時間( 毫秒)                 

25155

17500

19000

16500

情境二時間( 毫秒 )

69000

67031

74031

71016

5.    nio.charset

字元編碼解碼 : 位元組碼本身只是一些數字,放到正確的上下文中被正確被解析。向 ByteBuffer 中存放資料時需要考慮字元集的編碼方式,讀取展示 ByteBuffer 資料時涉及對字元集解碼。

Java.nio.charset 提供了編碼解碼一套解決方案。

以我們最常見的 http 請求為例,在請求的時候必須對請求進行正確的編碼。在得到響應時必須對響應進行正確的解碼。

以下代碼向 baidu 發一次請求,並擷取結果進行顯示。例子示範到了 charset 的使用。

例子 2BaiduReader.java Java代碼    package nio.readpage;      import java.nio.ByteBuffer;   import java.nio.channels.SocketChannel;   import java.nio.charset.Charset;   import java.net.InetSocketAddress;   import java.io.IOException;   public class BaiduReader {       private Charset charset = Charset.forName("GBK");// 建立GBK字元集       private SocketChannel channel;       public void readHTMLContent() {           try {               InetSocketAddress socketAddress = new InetSocketAddress(   "www.baidu.com", 80);   //step1:開啟串連               channel = SocketChannel.open(socketAddress);           //step2:發送請求,使用GBK編碼               channel.write(charset.encode("GET " + "/ HTTP/1.1" + "\r\n\r\n"));               //step3:讀取資料               ByteBuffer buffer = ByteBuffer.allocate(1024);// 建立1024位元組的緩衝               while (channel.read(buffer) != -1) {                   buffer.flip();// flip方法在讀緩衝區位元組操作之前調用。                   System.out.println(charset.decode(buffer));                   // 使用Charset.decode方法將位元組轉換為字串                   buffer.clear();// 清空緩衝  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.