當前位置:編程學習大全網 - 編程語言 - java nio 開發實例

java nio 開發實例

 首先了解下所謂的java nio是個什麽東西!

 傳統的並發型服務器設計是利用阻塞型網絡I/O 以多線程的模式來實現的 然而由

 於系統常常在進行網絡讀寫時處於阻塞狀態 會大大影響系統的性能 自Java 開始引入

 了NIO(新I/O) API 通過使用非阻塞型I/O 實現流暢的網絡讀寫操作 為開發高性能並發

 型服務器程序提供了壹個很好的解決方案 這就是java nio

 首先來看下傳統的阻塞型網絡 I/O的不足

 Java 平臺傳統的I/O 系統都是基於Byte(字節)和Stream(數據流)的 相應的I/O 操

 作都是阻塞型的 所以服務器程序也采用阻塞型I/O 進行數據的讀 寫操作 本文以TCP

 長連接模式來討論並發型服務器的相關設計 為了實現服務器程序的並發性要求 系統由壹

 個單獨的主線程來監聽用戶發起的連接請求 壹直處於阻塞狀態 當有用戶連接請求到來時

 程序都會啟壹個新的線程來統壹處理用戶數據的讀 寫操作

 這種模式的優點是簡單 實用 易管理 然而缺點也是顯而易見的 由於是為每壹個客

 戶端分配壹個線程來處理輸入 輸出數據 其線程與客戶機的比例近似為 隨著線程

 數量的不斷增加 服務器啟動了大量的並發線程 會大大加大系統對線程的管理開銷 這將

 成為吞吐量瓶頸的主要原因 其次由於底層的I/O 操作采用的同步模式 I/O 操作的阻塞管

 理粒度是以服務於請求的線程為單位的 有可能大量的線程會閑置 處於盲等狀態 造成I/O

 資源利用率不高 影響整個系統的性能

 對於並發型服務器 系統用在阻塞型I/O 等待和線程間切換的時間遠遠多於CPU 在內

 存中處理數據的時間 因此傳統的阻塞型I/O 已經成為制約系統性能的瓶頸 Java 版本

 後推出的NIO 工具包 提供了非阻塞型I/O 的異步輸入輸出機制 為提高系統的性能提供

 了可實現的基礎機制

 NIO 包及工作原理

 針對傳統I/O 工作模式的不足 NIO 工具包提出了基於Buffer(緩沖區) Channel(通

 道) Selector(選擇器)的新模式 Selector(選擇器) 可選擇的Channel(通道)和

 SelectionKey(選擇鍵)配合起來使用 可以實現並發的非阻塞型I/O 能力

 NIO 工具包的成員

 Buffer(緩沖器)

 Buffer 類是壹個抽象類 它有 個子類分別對應於七種基本的數據類型 ByteBuffer

 CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer 和ShortBuffer 每壹個Buffer

 對象相當於壹個數據容器 可以把它看作內存中的壹個大的數組 用來存儲和提取所有基本

 類型(boolean 型除外)的數據 Buffer 類的核心是壹塊內存區 可以直接對其執行與內存有關

 的操作 利用操作系統特性和能力提高和改善Java 傳統I/O 的性能

 Channel(通道)

 Channel 被認為是NIO 工具包的壹大創新點 是(Buffer)緩沖器和I/O 服務之間的通道

 具有雙向性 既可以讀入也可以寫出 可以更高效的傳遞數據 我們這裏主要討論

 ServerSocketChannel 和SocketChannel 它們都繼承了SelectableChannel 是可選擇的通道

 分別可以工作在同步和異步兩種方式下(這裏的可選擇不是指可以選擇兩種工作方式 而是

 指可以有選擇的註冊自己感興趣的事件) 當通道工作在同步方式時 它的功能和編程方法

 與傳統的ServerSocket Socket 對象相似 當通道工作在異步工作方式時 進行輸入輸出處

 理不必等到輸入輸出完畢才返回 並且可以將其感興趣的(如 接受操作 連接操作 讀出

 操作 寫入操作)事件註冊到Selector 對象上 與Selector 對象協同工作可以更有效率的支

 持和管理並發的網絡套接字連接

 Selector(選擇器)和SelectionKey(選擇鍵)

 各類 Buffer 是數據的容器對象 各類Channel 實現在各類Buffer 與各類I/O 服務間傳輸

 數據 Selector 是實現並發型非阻塞I/O 的核心 各種可選擇的通道將其感興趣的事件註冊

 到Selector 對象上 Selector 在壹個循環中不斷輪循監視這各些註冊在其上的Socket 通道

 SelectionKey 類則封裝了SelectableChannel 對象在Selector 中的註冊信息 當Selector 監測

 到在某個註冊的SelectableChannel 上發生了感興趣的事件時 自動激活產生壹個SelectionKey

 對象 在這個對象中記錄了哪壹個SelectableChannel 上發生了哪種事件 通過對被激活的

 SelectionKey 的分析 外界可以知道每個SelectableChannel 發生的具體事件類型 進行相應的

 處理

 NIO 工作原理

 通過上面的討論 我們可以看出在並發型服務器程序中使用NIO 實際上是通過網絡事

 件驅動模型實現的 我們應用Select 機制 不用為每壹個客戶端連接新啟線程處理 而是將

 其註冊到特定的Selector 對象上 這就可以在單線程中利用Selector 對象管理大量並發的網

 絡連接 更好的利用了系統資源 采用非阻塞I/O 的通信方式 不要求阻塞等待I/O 操作完

 成即可返回 從而減少了管理I/O 連接導致的系統開銷 大幅度提高了系統性能

 當有讀或寫等任何註冊的事件發生時 可以從Selector 中獲得相應的

 SelectionKey 從SelectionKey 中可以找到發生的事件和該事件所發生的具體的

 SelectableChannel 以獲得客戶端發送過來的數據 由於在非阻塞網絡I/O 中采用了事件觸

 發機制 處理程序可以得到系統的主動通知 從而可以實現底層網絡I/O 無阻塞 流暢地讀

 寫 而不像在原來的阻塞模式下處理程序需要不斷循環等待 使用NIO 可以編寫出性能更

 好 更易擴展的並發型服務器程序

 並發型服務器程序的實現代碼

 應用 NIO 工具包 基於非阻塞網絡I/O 設計的並發型服務器程序與以往基於阻塞I/O 的

 實現程序有很大不同 在使用非阻塞網絡I/O 的情況下 程序讀取數據和寫入數據的時機不

 是由程序員控制的 而是Selector 決定的 下面便給出基於非阻塞網絡I/O 的並發型服務器

 程序的核心代碼片段

 import java io * //引入Java io包

 import * //引入包

 import java nio channels * //引入Java nio channels包

 import java util * //引入Java util包

 public class TestServer implements Runnable

 {

 /**

 * 服務器Channel對象 負責接受用戶連接

 */

 private ServerSocketChannel server

 /**

 * Selector對象 負責監控所有的連接到服務器的網絡事件的發生

 */

 private Selector selector

 /**

 * 總的活動連接數

 */

 private int activeSockets

 /**

 * 服務器Channel綁定的端口號

 */

 private int port

 /**

 *

 * 構造函數

 */

 public TestServer()throws IOException

 {

 activeSockets=

 port= //初始化服務器Channel綁定的端口號為

 selector= Selector open() //初始化Selector對象

 server=ServerSocketChannel open() //初始化服務器Channel對象

 ServerSocket socket=server socket() //獲取服務器Channel對應的//ServerSocket對象

 socket bind(new InetSocketAddress(port)) //把Socket綁定到監聽端口 上

 nfigureBlocking(false) //將服務器Channel設置為非阻塞模式

 server register(selector SelectionKey OP_ACCEPT) //將服務器Channel註冊到

 Selector對象 並指出服務器Channel所感興趣的事件為可接受請求操作

 }

 public void run()

 {

 while(true)

 {

 try

 {

 /**

 *應用Select機制輪循是否有用戶感興趣的新的網絡事件發生 當沒有

 * 新的網絡事件發生時 此方法會阻塞 直到有新的網絡事件發生為止

 */

 selector select()

 }

 catch(IOException e)

 {

 continue //當有異常發生時 繼續進行循環操作

 }

 /**

 * 得到活動的網絡連接選擇鍵的集合

 */

 Set<SelectionKey> keys=selector selectedKeys()

 activeSockets=keys size() //獲取活動連接的數目

 if(activeSockets== )

 {

 continue //如果連接數為 則繼續進行循環操作

 }

 /**

 /**

 * 應用For—Each循環遍歷整個選擇鍵集合

 */

 for(SelectionKey key :keys)

 {

 /**

 * 如果關鍵字狀態是為可接受 則接受連接 註冊通道 以接受更多的*

 事件 進行相關的服務器程序處理

 */

 if(key isAcceptable())

 {

 doServerSocketEvent(key)

 continue

 }

 /**

 * 如果關鍵字狀態為可讀 則說明Channel是壹個客戶端的連接通道

 * 進行相應的讀取客戶端數據的操作

 */

 if(key isReadable())

 {

 doClientReadEvent(key)

 continue

 }

 /**

 * 如果關鍵字狀態為可寫 則也說明Channel是壹個客戶端的連接通道

 * 進行相應的向客戶端寫數據的操作

 */

 if(key isWritable())

 {

 doClinetWriteEvent(key)

 continue

 }

 }

 }

 }

 /**

 * 處理服務器事件操作

 * @param key 服務器選擇鍵對象

 */

 private void doServerSocketEvent(SelectionKey key)

 {

 SocketChannel client=null

 try

 {

 ServerSocketChannel server=(ServerSocketChannel)key channel()

 client=server accept()

 if(client==null)

 {

 return

 }

 nfigureBlocking(false) //將客戶端Channel設置為非阻塞型

 /**

 /**

 * 將客戶端Channel註冊到Selector對象上 並且指出客戶端Channel所感

 * 興趣的事件為可讀和可寫

 */

 client register(selector SelectionKey OP_READ|SelectionKey OP_READ)

 }catch(IOException e)

 {

 try

 {

 client close()

 }catch(IOException e ){}

 }

 }

 /**

 * 進行向客戶端寫數據操作

 * @param key 客戶端選擇鍵對象

 */

 private void doClinetWriteEvent(SelectionKey key)

 {

 代碼實現略

 }

 /**

 * 進行讀取客戶短數據操作

 * @param key 客戶端選擇鍵對象

 */

 private void doClientReadEvent(SelectionKey key)

 {

 代碼實現略

 }

 }

 從上面對代碼可以看出 使用非阻塞性I/O進行並發型服務器程序設計分三個部分

 向Selector對象註冊感興趣的事件 從Selector中獲取所感興趣的事件 根據不同的事件進

 行相應的處理

 結語

 通過使用NIO 工具包進行並發型服務器程序設計 壹個或者很少幾個Socket 線程就可

 以處理成千上萬個活動的Socket 連接 大大降低了服務器端程序的開銷 同時網絡I/O 采取

 非阻塞模式 線程不再在讀或寫時阻塞 操作系統可以更流暢的讀寫數據並可以更有效地向

 CPU 傳遞數據進行處理 以便更有效地提高系統的性能

 看到這裏相信妳看了不止 分鐘了吧 ? 我說 分鐘其實就是想讓大家能夠輕松的讀下去(雞蛋 )

 好了 到這裏大家應該對java nio有個初步的了解了吧~~~

lishixinzhi/Article/program/Java/hx/201311/27190

  • 上一篇:豬簡單的豬怎麽畫
  • 下一篇:請問壹下TC到底是什麽啊?
  • copyright 2024編程學習大全網