java BIO NIO AIO 理论篇
http://furturestrategist.iteye.com/blog/1463369
java中的IO主要源自于網絡和本地文件
?
???? IO的方式通常分為幾種,同步阻塞的BIO、同步非阻塞的NIO、異步非阻塞的AIO
???? 在JDK1.4出來之前,我們建立網絡連接的時候采用BIO模式,需要先在服務端啟動一個ServerSocket,然后在客戶端啟動Socket來對服務端進行通信,默認情況下服務端需要對每個請求建立一堆線程等待請求,而客戶端發送請求后,先咨詢服務端是否有線程相應,如果沒有則會一直等待或者遭到拒絕請求,如果有的話,客戶端會線程會等待請求結束后才繼續執行。
?
???? BIO與NIO一個比較重要的不同,是我們使用BIO的時候往往會引入多線程,每個連接一個單獨的線程;而NIO則是使用單線程或者只使用少量的多線程,每個連接共用一個線程。
???
????
????? NIO的最重要的地方是當一個連接創建后,不需要對應一個線程,這個連接會被注冊到多路復用器上面,所以所有的連接只需要一個線程就可以搞定,當這個線程中的多路復用器進行輪詢的時候,發現連接上有請求的話,才開啟一個線程進行處理,也就是一個請求一個線程模式。
?
?
????? 在NIO的處理方式中,當一個請求來的話,開啟線程進行處理,可能會等待后端應用的資源(JDBC連接等),其實這個線程就被阻塞了,當并發上來的話,還是會有BIO一樣的問題。
HTTP/1.1出現后,有了Http長連接,這樣除了超時和指明特定關閉的http header外,這個鏈接是一直打開的狀態的,這樣在NIO處理中可以進一步的進化,在后端資源中可以實現資源池或者隊列,當請求來的話,開啟的線程把請求和請求數據傳送給后端資源池或者隊列里面就返回,并且在全局的地方保持住這個現場(哪個連接的哪個請求等),這樣前面的線程還是可以去接受其他的請求,而后端的應用的處理只需要執行隊列里面的就可以了,這樣請求處理和后端應用是異步的.當后端處理完,到全局地方得到現場,產生響應,這個就實現了異步處理。
?
???? BIO是一個連接一個線程。
? NIO是一個請求一個線程。
? AIO是一個有效請求一個線程。
?
?
========http://xm-king.iteye.com/blog/766330
最近一直在忙著JAVA NIO的知識,花了一下午的時間,總算寫出了一個可以運行的程序,廢話少說,上代碼!
Java代碼 import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set;public class NIOServer {/*標識數字*/private int flag = 0;/*緩沖區大小*/private int BLOCK = 4096;/*接受數據緩沖區*/private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);/*發送數據緩沖區*/private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);private Selector selector;public NIOServer(int port) throws IOException {// 打開服務器套接字通道ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 服務器配置為非阻塞serverSocketChannel.configureBlocking(false);// 檢索與此通道關聯的服務器套接字ServerSocket serverSocket = serverSocketChannel.socket();// 進行服務的綁定serverSocket.bind(new InetSocketAddress(port));// 通過open()方法找到Selectorselector = Selector.open();// 注冊到selector,等待連接serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("Server Start----8888:");}// 監聽private void listen() throws IOException {while (true) {// 選擇一組鍵,并且相應的通道已經打開selector.select();// 返回此選擇器的已選擇鍵集。Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next();iterator.remove();handleKey(selectionKey);}}}// 處理請求private void handleKey(SelectionKey selectionKey) throws IOException {// 接受請求ServerSocketChannel server = null;SocketChannel client = null;String receiveText;String sendText;int count=0;// 測試此鍵的通道是否已準備好接受新的套接字連接。if (selectionKey.isAcceptable()) {// 返回為之創建此鍵的通道。server = (ServerSocketChannel) selectionKey.channel();// 接受到此通道套接字的連接。// 此方法返回的套接字通道(如果有)將處于阻塞模式。client = server.accept();// 配置為非阻塞client.configureBlocking(false);// 注冊到selector,等待連接client.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) {// 返回為之創建此鍵的通道。client = (SocketChannel) selectionKey.channel();//將緩沖區清空以備下次讀取receivebuffer.clear();//讀取服務器發送來的數據到緩沖區中count = client.read(receivebuffer); if (count > 0) {receiveText = new String( receivebuffer.array(),0,count);System.out.println("服務器端接受客戶端數據--:"+receiveText);client.register(selector, SelectionKey.OP_WRITE);}} else if (selectionKey.isWritable()) {//將緩沖區清空以備下次寫入sendbuffer.clear();// 返回為之創建此鍵的通道。client = (SocketChannel) selectionKey.channel();sendText="message from server--" + flag++;//向緩沖區中輸入數據sendbuffer.put(sendText.getBytes());//將緩沖區各標志復位,因為向里面put了數據標志被改變要想從中讀取數據發向服務器,就要復位sendbuffer.flip();//輸出到通道client.write(sendbuffer);System.out.println("服務器端向客戶端發送數據--:"+sendText);client.register(selector, SelectionKey.OP_READ);}}/*** @param args* @throws IOException*/public static void main(String[] args) throws IOException {// TODO Auto-generated method stubint port = 8888;NIOServer server = new NIOServer(port);server.listen();} }?
Java代碼 import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set;public class NIOClient {/*標識數字*/private static int flag = 0;/*緩沖區大小*/private static int BLOCK = 4096;/*接受數據緩沖區*/private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);/*發送數據緩沖區*/private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);/*服務器端地址*/private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress("localhost", 1111);public static void main(String[] args) throws IOException {// TODO Auto-generated method stub// 打開socket通道SocketChannel socketChannel = SocketChannel.open();// 設置為非阻塞方式socketChannel.configureBlocking(false);// 打開選擇器Selector selector = Selector.open();// 注冊連接服務端socket動作socketChannel.register(selector, SelectionKey.OP_CONNECT);// 連接socketChannel.connect(SERVER_ADDRESS);// 分配緩沖區大小內存Set<SelectionKey> selectionKeys;Iterator<SelectionKey> iterator;SelectionKey selectionKey;SocketChannel client;String receiveText;String sendText;int count=0;while (true) {//選擇一組鍵,其相應的通道已為 I/O 操作準備就緒。//此方法執行處于阻塞模式的選擇操作。selector.select();//返回此選擇器的已選擇鍵集。selectionKeys = selector.selectedKeys();//System.out.println(selectionKeys.size());iterator = selectionKeys.iterator();while (iterator.hasNext()) {selectionKey = iterator.next();if (selectionKey.isConnectable()) {System.out.println("client connect");client = (SocketChannel) selectionKey.channel();// 判斷此通道上是否正在進行連接操作。// 完成套接字通道的連接過程。if (client.isConnectionPending()) {client.finishConnect();System.out.println("完成連接!");sendbuffer.clear();sendbuffer.put("Hello,Server".getBytes());sendbuffer.flip();client.write(sendbuffer);}client.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) {client = (SocketChannel) selectionKey.channel();//將緩沖區清空以備下次讀取receivebuffer.clear();//讀取服務器發送來的數據到緩沖區中count=client.read(receivebuffer);if(count>0){receiveText = new String( receivebuffer.array(),0,count);System.out.println("客戶端接受服務器端數據--:"+receiveText);client.register(selector, SelectionKey.OP_WRITE);}} else if (selectionKey.isWritable()) {sendbuffer.clear();client = (SocketChannel) selectionKey.channel();sendText = "message from client--" + (flag++);sendbuffer.put(sendText.getBytes());//將緩沖區各標志復位,因為向里面put了數據標志被改變要想從中讀取數據發向服務器,就要復位sendbuffer.flip();client.write(sendbuffer);System.out.println("客戶端向服務器端發送數據--:"+sendText);client.register(selector, SelectionKey.OP_READ);}}selectionKeys.clear();}} }?????????? 個人感覺,JAVA NIO的操作時麻煩了不少,但是無疑這樣做效率會得到很大的提升。
?
總結
以上是生活随笔為你收集整理的java BIO NIO AIO 理论篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java NIO使用及原理分析
- 下一篇: 在Win2003中安装bind【部署智能