自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java NIO開發(fā)實例

開發(fā) 后端
傳統(tǒng)的并發(fā)型服務(wù)器設(shè)計是利用阻塞型網(wǎng)絡(luò)I/O 以多線程的模式來實現(xiàn)的,然而由于系統(tǒng)常常在進行網(wǎng)絡(luò)讀寫時處于阻塞狀態(tài),會大大影響系統(tǒng)的性能;自Java1. 4 開始引入了NIO(新I/O) API,通過使用非阻塞型I/O,實現(xiàn)流暢的網(wǎng)絡(luò)讀寫操作,為開發(fā)高性能并發(fā)型服務(wù)器程序提供了一個很好的解決方案。這就是java nio

最近一直在研究java nio,提出一點淺見,希望能和大家分享!??!廢話不多說了,直接進入主題!

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

傳統(tǒng)的并發(fā)型服務(wù)器設(shè)計是利用阻塞型網(wǎng)絡(luò)I/O 以多線程的模式來實現(xiàn)的,然而由于系統(tǒng)常常在進行網(wǎng)絡(luò)讀寫時處于阻塞狀態(tài),會大大影響系統(tǒng)的性能;自Java1. 4 開始引入了NIO(新I/O) API,通過使用非阻塞型I/O,實現(xiàn)流暢的網(wǎng)絡(luò)讀寫操作,為開發(fā)高性能并發(fā)型服務(wù)器程序提供了一個很好的解決方案。這就是java nio

首先來看下傳統(tǒng)的阻塞型網(wǎng)絡(luò)I/O的不足

Java 平臺傳統(tǒng)的I/O 系統(tǒng)都是基于Byte(字節(jié))和Stream(數(shù)據(jù)流)的,相應(yīng)的I/O 操作都是阻塞型的,所以服務(wù)器程序也采用阻塞型I/O 進行數(shù)據(jù)的讀、寫操作。本文以TCP長連接模式來討論并發(fā)型服務(wù)器的相關(guān)設(shè)計,為了實現(xiàn)服務(wù)器程序的并發(fā)性要求,系統(tǒng)由一個單獨的主線程來監(jiān)聽用戶發(fā)起的連接請求,一直處于阻塞狀態(tài);當(dāng)有用戶連接請求到來時,程序都會啟一個新的線程來統(tǒng)一處理用戶數(shù)據(jù)的讀、寫操作。

這種模式的優(yōu)點是簡單、實用、易管理;然而缺點也是顯而易見的:由于是為每一個客戶端分配一個線程來處理輸入、輸出數(shù)據(jù),其線程與客戶機的比例近似為1:1,隨著線程數(shù)量的不斷增加,服務(wù)器啟動了大量的并發(fā)線程,會大大加大系統(tǒng)對線程的管理開銷,這將成為吞吐量瓶頸的主要原因;其次由于底層的I/O 操作采用的同步模式,I/O 操作的阻塞管理粒度是以服務(wù)于請求的線程為單位的,有可能大量的線程會閑置,處于盲等狀態(tài),造成I/O資源利用率不高,影響整個系統(tǒng)的性能。

對于并發(fā)型服務(wù)器,系統(tǒng)用在阻塞型I/O 等待和線程間切換的時間遠遠多于CPU 在內(nèi)存中處理數(shù)據(jù)的時間,因此傳統(tǒng)的阻塞型I/O 已經(jīng)成為制約系統(tǒng)性能的瓶頸。Java1.4 版本后推出的NIO 工具包,提供了非阻塞型I/O 的異步輸入輸出機制,為提高系統(tǒng)的性能提供了可實現(xiàn)的基礎(chǔ)機制。

NIO 包及工作原理

針對傳統(tǒng)I/O 工作模式的不足,NIO 工具包提出了基于Buffer(緩沖區(qū))、Channel(通道)、Selector(選擇器)的新模式;Selector(選擇器)、可選擇的Channel(通道)和SelectionKey(選擇鍵)配合起來使用,可以實現(xiàn)并發(fā)的非阻塞型I/O 能力。

NIO 工具包的成員

Buffer(緩沖器)

Buffer 類是一個抽象類,它有7 個子類分別對應(yīng)于七種基本的數(shù)據(jù)類型:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer 和ShortBuffer。每一個Buffer對象相當(dāng)于一個數(shù)據(jù)容器,可以把它看作內(nèi)存中的一個大的數(shù)組,用來存儲和提取所有基本類型(boolean 型除外)的數(shù)據(jù)。Buffer 類的核心是一塊內(nèi)存區(qū),可以直接對其執(zhí)行與內(nèi)存有關(guān)的操作,利用操作系統(tǒng)特性和能力提高和改善Java 傳統(tǒng)I/O 的性能。

Channel(通道)

Channel 被認為是NIO 工具包的一大創(chuàng)新點,是(Buffer)緩沖器和I/O 服務(wù)之間的通道,具有雙向性,既可以讀入也可以寫出,可以更高效的傳遞數(shù)據(jù)。我們這里主要討ServerSocketChannel 和SocketChannel,它們都繼承了SelectableChannel,是可選擇的通道,分別可以工作在同步和異步兩種方式下(這里的可選擇不是指可以選擇兩種工作方式,而是指可以有選擇的注冊自己感興趣的事件)。當(dāng)通道工作在同步方式時,它的功能和編程方法與傳統(tǒng)的ServerSocket、Socket 對象相似;當(dāng)通道工作在異步工作方式時,進行輸入輸出處理不必等到輸入輸出完畢才返回,并且可以將其感興趣的(如:接受操作、連接操作、讀出操作、寫入操作)事件注冊到Selector 對象上,與Selector 對象協(xié)同工作可以更有效率的支持和管理并發(fā)的網(wǎng)絡(luò)套接字連接。

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

各類 Buffer 是數(shù)據(jù)的容器對象;各類Channel 實現(xiàn)在各類Buffer 與各類I/O 服務(wù)間傳輸數(shù)據(jù)。Selector 是實現(xiàn)并發(fā)型非阻塞I/O 的核心,各種可選擇的通道將其感興趣的事件注冊到Selector 對象上,Selector 在一個循環(huán)中不斷輪循監(jiān)視這各些注冊在其上的Socket 通道。SelectionKey 類則封裝了SelectableChannel 對象在Selector 中的注冊信息。當(dāng)Selector 監(jiān)測到在某個注冊的SelectableChannel 上發(fā)生了感興趣的事件時,自動激活產(chǎn)生一個SelectionKey對象,在這個對象中記錄了哪一個SelectableChannel 上發(fā)生了哪種事件,通過對被激活的SelectionKey 的分析,外界可以知道每個SelectableChannel 發(fā)生的具體事件類型,進行相應(yīng)的處理。

NIO 工作原理

通過上面的討論,我們可以看出在并發(fā)型服務(wù)器程序中使用NIO,實際上是通過網(wǎng)絡(luò)事件驅(qū)動模型實現(xiàn)的。我們應(yīng)用Select 機制,不用為每一個客戶端連接新啟線程處理,而是將其注冊到特定的Selector 對象上,這就可以在單線程中利用Selector 對象管理大量并發(fā)的網(wǎng)絡(luò)連接,更好的利用了系統(tǒng)資源;采用非阻塞I/O 的通信方式,不要求阻塞等待I/O 操作完成即可返回,從而減少了管理I/O 連接導(dǎo)致的系統(tǒng)開銷,大幅度提高了系統(tǒng)性能。

當(dāng)有讀或?qū)懙热魏巫缘氖录l(fā)生時,可以從Selector 中獲得相應(yīng)的SelectionKey , 從SelectionKey 中可以找到發(fā)生的事件和該事件所發(fā)生的具體的SelectableChannel,以獲得客戶端發(fā)送過來的數(shù)據(jù)。由于在非阻塞網(wǎng)絡(luò)I/O 中采用了事件觸發(fā)機制,處理程序可以得到系統(tǒng)的主動通知,從而可以實現(xiàn)底層網(wǎng)絡(luò)I/O 無阻塞、流暢地讀寫,而不像在原來的阻塞模式下處理程序需要不斷循環(huán)等待。使用NIO,可以編寫出性能更好、更易擴展的并發(fā)型服務(wù)器程序。

并發(fā)型服務(wù)器程序的實現(xiàn)代碼

應(yīng)用 NIO 工具包,基于非阻塞網(wǎng)絡(luò)I/O 設(shè)計的并發(fā)型服務(wù)器程序與以往基于阻塞I/O 的實現(xiàn)程序有很大不同,在使用非阻塞網(wǎng)絡(luò)I/O 的情況下,程序讀取數(shù)據(jù)和寫入數(shù)據(jù)的時機不是由程序員控制的,而是Selector 決定的。下面便給出基于非阻塞網(wǎng)絡(luò)I/O 的并發(fā)型服務(wù)器程序的核心代碼片段:

  1. import java.io.*; //引入Java.io包  
  2. import java.net.*; //引入Java.net包  
  3. import java.nio.channels.*; //引入Java.nio.channels包  
  4. import java.util.*; //引入Java.util包  
  5. public class TestServer implements Runnable  
  6.  
  7. {  
  8. /**  
  9.  
  10. * 服務(wù)器Channel對象,負責(zé)接受用戶連接  
  11. */ 
  12. private ServerSocketChannel server;  
  13. /**  
  14. * Selector對象,負責(zé)監(jiān)控所有的連接到服務(wù)器的網(wǎng)絡(luò)事件的發(fā)生  
  15. */ 
  16. private Selector selector;  
  17. /**  
  18. * 總的活動連接數(shù)  
  19. */ 
  20. private int activeSockets;  
  21. /**  
  22. * 服務(wù)器Channel綁定的端口號  
  23. */ 
  24. private int port ;  
  25. /**  
  26. *  
  27. * 構(gòu)造函數(shù)  
  28. */ 
  29. public TestServer()throws IOException  
  30. {  
  31. activeSockets=0;  
  32. port=9999;//初始化服務(wù)器Channel綁定的端口號為9999  
  33. selector= Selector.open();//初始化Selector對象  
  34. server=ServerSocketChannel.open();//初始化服務(wù)器Channel對象  
  35. ServerSocket socket=server.socket();//獲取服務(wù)器Channel對應(yīng)的//ServerSocket對象  
  36. socket.bind(new InetSocketAddress(port));//把Socket綁定到監(jiān)聽端口9999上  
  37. server.configureBlocking(false);//將服務(wù)器Channel設(shè)置為非阻塞模式  
  38. server.register(selector,SelectionKey.OP_ACCEPT);//將服務(wù)器Channel注冊到  
  39. Selector對象,并指出服務(wù)器Channel所感興趣的事件為可接受請求操作  
  40. }  
  41. public void run()  
  42. {  
  43. while(true)  
  44. {  
  45. try 
  46. {  
  47. /**  
  48. *應(yīng)用Select機制輪循是否有用戶感興趣的新的網(wǎng)絡(luò)事件發(fā)生,當(dāng)沒有  
  49.  
  50. * 新的網(wǎng)絡(luò)事件發(fā)生時,此方法會阻塞,直到有新的網(wǎng)絡(luò)事件發(fā)生為止  
  51. */ 
  52. selector.select();  
  53.  
  54. }  
  55. catch(IOException e)  
  56. {  
  57. continue;//當(dāng)有異常發(fā)生時,繼續(xù)進行循環(huán)操作  
  58. }  
  59. /**  
  60. * 得到活動的網(wǎng)絡(luò)連接選擇鍵的集合  
  61. */ 
  62. Set<SelectionKey> keys=selector.selectedKeys();  
  63. activeSockets=keys.size();//獲取活動連接的數(shù)目  
  64. if(activeSockets==0)  
  65. {  
  66. continue//如果連接數(shù)為0,則繼續(xù)進行循環(huán)操作  
  67. }  
  68. /**  
  69.  
  70. /**  
  71. * 應(yīng)用For—Each循環(huán)遍歷整個選擇鍵集合  
  72. */ 
  73. for(SelectionKey key :keys)  
  74. {  
  75. /**  
  76. * 如果關(guān)鍵字狀態(tài)是為可接受,則接受連接,注冊通道,以接受更多的*  
  77. 事件,進行相關(guān)的服務(wù)器程序處理  
  78. */ 
  79. if(key.isAcceptable())  
  80. {  
  81. doServerSocketEvent(key);  
  82. continue;  
  83. }  
  84. /**  
  85. * 如果關(guān)鍵字狀態(tài)為可讀,則說明Channel是一個客戶端的連接通道,  
  86. * 進行相應(yīng)的讀取客戶端數(shù)據(jù)的操作  
  87. */ 
  88. if(key.isReadable())  
  89. {  
  90. doClientReadEvent(key);  
  91. continue;  
  92. }  
  93. /**  
  94. * 如果關(guān)鍵字狀態(tài)為可寫,則也說明Channel是一個客戶端的連接通道,  
  95. * 進行相應(yīng)的向客戶端寫數(shù)據(jù)的操作  
  96. */ 
  97. if(key.isWritable())  
  98. {  
  99. doClinetWriteEvent(key);  
  100. continue;  
  101. }  
  102. }  
  103. }  
  104. }  
  105.  
  106. /**  
  107. * 處理服務(wù)器事件操作  
  108. * @param key 服務(wù)器選擇鍵對象  
  109. */ 
  110. private void doServerSocketEvent(SelectionKey key)  
  111. {  
  112. SocketChannel client=null;  
  113. try 
  114. {  
  115. ServerSocketChannel server=(ServerSocketChannel)key.channel();  
  116. client=server.accept();  
  117. if(client==null)  
  118. {  
  119. return;  
  120. }  
  121. client.configureBlocking(false);//將客戶端Channel設(shè)置為非阻塞型  
  122. /**  
  123.  
  124. /**  
  125. * 將客戶端Channel注冊到Selector對象上,并且指出客戶端Channel所感  
  126. * 興趣的事件為可讀和可寫  
  127. */ 
  128. client.register(selector,SelectionKey.OP_READ|SelectionKey.OP_READ);  
  129. }catch(IOException e)  
  130. {  
  131. try 
  132. {  
  133. client.close();  
  134.  
  135. }catch(IOException e1){}  
  136. }  
  137. }  
  138. /**  
  139. * 進行向客戶端寫數(shù)據(jù)操作  
  140. * @param key 客戶端選擇鍵對象  
  141. */ 
  142. private void doClinetWriteEvent(SelectionKey key)  
  143. {  
  144. 代碼實現(xiàn)略;  
  145. }  
  146. /**  
  147. * 進行讀取客戶短數(shù)據(jù)操作  
  148. * @param key 客戶端選擇鍵對象  
  149. */ 
  150. private void doClientReadEvent(SelectionKey key)  
  151. {  
  152. 代碼實現(xiàn)略;  
  153. }  

從上面對代碼可以看出,使用非阻塞性I/O進行并發(fā)型服務(wù)器程序設(shè)計分三個部分:1.向Selector對象注冊感興趣的事件;2.從Selector中獲取所感興趣的事件;3.根據(jù)不同的事件進行相應(yīng)的處理。

結(jié)  語

通過使用NIO 工具包進行并發(fā)型服務(wù)器程序設(shè)計,一個或者很少幾個Socket 線程就可以處理成千上萬個活動的Socket 連接,大大降低了服務(wù)器端程序的開銷;同時網(wǎng)絡(luò)I/O 采取非阻塞模式,線程不再在讀或?qū)憰r阻塞,操作系統(tǒng)可以更流暢的讀寫數(shù)據(jù)并可以更有效地向CPU 傳遞數(shù)據(jù)進行處理,以便更有效地提高系統(tǒng)的性能。

原文鏈接:http://androidssh.iteye.com/blog/797910

【編輯推薦】

  1. Java NIO 聊天室實例
  2. 多線程NIO客戶端實例
  3. 用nio實現(xiàn)Echo服務(wù)
  4. Java NIO 深入研究
  5. Java NIO聊天窗口實例
責(zé)任編輯:林師授 來源: androidssh的博客
相關(guān)推薦

2011-12-15 10:10:33

Javanio

2011-12-07 14:41:51

JavaNIO

2011-12-15 11:11:51

JavaNIO

2011-12-15 10:19:55

JavaNIO

2011-12-15 11:03:21

JavaNIO

2011-12-15 11:39:25

JavaNIO

2011-12-15 09:40:06

Javanio

2011-12-15 09:55:47

javanio

2011-12-07 14:57:44

JavaNIO

2022-02-22 08:00:48

JavaNIOBuffer

2011-12-15 10:43:20

JavaNIO

2015-09-25 09:14:50

java緩沖技術(shù)

2011-12-07 16:12:29

JavaNIO

2011-12-02 13:16:14

JavaNIO

2011-12-08 13:23:00

JavaNIO

2011-12-07 15:58:25

JavaNIO

2011-12-14 10:31:43

2011-12-13 17:31:07

2021-12-27 10:20:46

JavaNetty網(wǎng)絡(luò)

2011-12-07 17:17:02

JavaNIO
點贊
收藏

51CTO技術(shù)棧公眾號