程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java NIO(一)入門篇

Java NIO(一)入門篇

編輯:JAVA綜合教程

Java NIO(一)入門篇


概念

java.nio(java new IO),是jdk1.4 裡提供的新api ,為所有的原始類型提供緩存支持。Sun 官方標榜的特性如下: 為所有的原始類型提供(Buffer)緩存支持。字符集編碼解碼解決方案。 Channel :一個新的原始I/O 抽象。 支持鎖和內存映射文件的文件訪問接口。 提供多路(non-bloking) 非阻塞式的高伸縮性網絡I/O。
 

NIO和IO的主要差別

IO NIO

面向流 面向緩沖

阻塞IO 非阻塞IO

無 selector

無 channel

面向流與面向緩沖

Java NIO和IO之間第一個最大的區別是,IO是面向流的,NIO是面向緩沖區的。Java IO面向流意味著每次從流中讀一個或多個字節,直至讀取所有字節,它們沒有被緩存在任何地方。比如InputStream只能進行讀取操作,而OutputStream只能進行寫操作。Java NIO 提供 了channel,Channel和傳統IO中的Stream很相似。雖然很相似,但是有很大的區別,主要區別為:通道是雙向的,通過一個Channel既可以進行讀,也可以進行寫;它將數據讀取到一個它稍後處理的緩沖區,需要時可在緩沖區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩沖區中包含所有您需要處理的數據。而且,需確保當更多的數據讀入緩沖區時,不要覆蓋緩沖區裡尚未處理的數據(如圖)。

\

阻塞與非阻塞IO

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

\

 

一個常見的網絡IO通訊流程如下:

\

 

從該網絡通訊過程來理解一下何為阻塞:

在以上過程中若連接還沒到來,那麼accept會阻塞,程序運行到這裡不得不掛起,CPU轉而執行其他線程。

在以上過程中若數據還沒准備好,read會一樣也會阻塞。

阻塞式網絡IO的特點:多線程處理多個連接。每個線程擁有自己的棧空間並且占用一些CPU時間。每個線程遇到外部為准備好的時候,都會阻塞掉。阻塞的結果就是會帶來大量的進程上下文切換。且大部分進程上下文切換可能是無意義的。比如假設一個線程監聽一個端口,一天只會有幾次請求進來,但是該cpu不得不為該線程不斷做上下文切換嘗試,大部分的切換以阻塞告終。

一個常見的網絡NIO通訊流程如下:

\

 

把整個過程切換成小的任務,通過任務間協作完成。

由一個專門的線程來處理所有的IO事件,並負責分發。

事件驅動機制:事件到的時候觸發,而不是同步的去監視事件。

線程通訊:線程之間通過wait,notify等方式通訊。保證每次上下文切換都是有意義的。減少無謂的進程切換。

 

選擇器(Selectors)

 

Selector類是NIO的核心類,Selector能夠檢測多個注冊的通道上是否有事件發生,如果有事件發生,便獲取事件然後針對每個事件進行相應的響應處理。這樣一來,只是用一個單線程就可以管理多個通道,也就是管理多個連接。這樣使得只有在連接真正有讀寫事件發生時,才會調用函數來進行讀寫,就大大地減少了系統開銷,並且不必為每個連接都創建一個線程,不用去維護多個線程,並且避免了多線程之間的上下文切換導致的開銷。

與Selector有關的一個關鍵類是SelectionKey,一個SelectionKey表示一個到達的事件,這2個類構成了服務端處理業務的關鍵邏輯。

channel

在前面已經提到,Channel和傳統IO中的Stream很相似。雖然很相似,但是有很大的區別,主要區別為:通道是雙向的,通過一個Channel既可以進行讀,也可以進行寫;而Stream只能進行單向操作,通過一個Stream只能進行讀或者寫;

以下是常用的幾種通道:

  • FileChannel
  • SocketChanel
  • ServerSocketChannel
  • DatagramChannel

      通過使用FileChannel可以從文件讀或者向文件寫入數據;通過SocketChannel,以TCP來向網絡連接的兩端讀寫數據;通過ServerSocketChanel能夠監聽客戶端發起的TCP連接,並為每個TCP連接創建一個新的SocketChannel來進行數據讀寫;通過DatagramChannel,以UDP協議來向網絡連接的兩端讀寫數據。

    下面給出通過FileChannel來向文件中寫入數據的一個例子:

    publicclassTest { publicstaticvoidmain(String[] args)throwsIOException { File file =newFile("data.txt"); FileOutputStream outputStream =newFileOutputStream(file); FileChannel channel = outputStream.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); String string ="java nio"; buffer.put(string.getBytes()); buffer.flip();//此處必須要調用buffer的flip方法 channel.write(buffer); channel.close(); outputStream.close(); } } 通過上面的程序會向工程目錄下的data.txt文件寫入字符串"java nio",注意在調用channel的write方法之前必須調用buffer的flip方法,否則無法正確寫入內容。
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved