nio是java的IO框架裏邊十分重要的一部份內容,其最核心的就是提供了非阻塞IO的處理方式,最典型的應用場景就是處理網絡鏈接。不少同窗提起nio都能提及一二,可是細究其背後的原理、思想每每就開始背書,說來講去都是那麼幾句,其中很多人並不見的真的很理解。本人以前就屬於此類,看了不少書和博客,可是大多數都只是講了三件套和怎麼使用,不多會很細緻的講背後的思想,那本次咱們就來扒一扒吧。
不少博客描述nio都是這麼說的:基於Reactor模式實現的多路非阻塞高性能的網絡IO。那麼咱們就從這個定義來分析,其中兩個關鍵點:多路非阻塞和Reactor模式。(原本想把高性能也算進去,可是後來想一想這個應該算前二者的結果)下邊咱們來分別搞懂這兩塊。html
多路非阻塞其實準確的名字叫作IO多路複用模型,其是linux五種網絡模型之一,也是當前網絡編程最常使用的模型之一。至於詳細的介紹請參考博客:高性能IO模型淺析(這個裏邊只給出了4中,沒有信號驅動IO,但講的很贊,特別是圖),這裏僅做簡要介紹和對比:java
對比以上五種模型能夠知道,IO複用模型從效率和實現成本綜合而言目前是比較好的選擇,這就是java基於該模型實現nio的根本緣由。上邊提到了IO複用模型的實現思想,其實這種思想在其餘語言中早已實現(如C++中聽說流弊哄哄超10w行代碼的ACE,自適配通訊環境,就採用了該模型),而且提出了一個叫Reactor的設計模式。react
Reactor模式,翻譯過來叫作反引器模式,其目的是在事件驅動的應用中,將一個請求的可以分離而且調度給應用程序。我相信大多數人都沒看明白前一句的意思(書仍是要背的),說白了就是對於一個請求的多個事件(如鏈接、讀寫等),通過這種模式的處理,可以區分出來,而且分別交給對應的處理模塊處理。廢話很少說,來看下一個簡圖:
linux
再來看個簡圖吧: 編程
基本上和Reactor能對應上,少了個dispatcher,這是因爲jdk自己提供的nio比較基本,dispatcher通常都由咱們本身實現,而在我理解中,mina、netty這些框架很重要的一方面也是提供了該部分的實現。
設計模式
從《netty權威指南》上抄了個例子以及配圖,並且代碼沒有客戶端的,你們能夠瞄一眼吧(爲何沒有?由於已經快一點了,我不想寫了......):
服務器端時序圖:數組
客戶端時序圖: 服務器
服務器端代碼:
網絡
package com.gj.netty.nio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.util.Iterator; import java.util.Set; /** * Created by guojing on 2015/6/7. */ public class MultiplexerTimerServer implements Runnable { private Selector selector; private ServerSocketChannel servChannel; private volatile boolean stop; public MultiplexerTimerServer(int port) { try { selector = Selector.open(); //新建多路複用selector servChannel = ServerSocketChannel.open(); //新建channel servChannel.configureBlocking(false); //設置非阻塞 servChannel.socket().bind(new InetSocketAddress(port),1024); //端口、塊大小 servChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("TimeServer is start, port:" + port); } catch (IOException e) { e.printStackTrace(); } } public void run() { while (!stop){ try { selector.select(1000); Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> ketIt = keys.iterator(); SelectionKey key = null; while (ketIt.hasNext()){ key = ketIt.next(); ketIt.remove(); //處理對應key事件 handler(key); } } catch (IOException e) { e.printStackTrace(); } } } private void handler(SelectionKey key){ //根據key去除channel作對應處理 } }
我想若是這會兒還有人記得標題必定會罵我了,丫的十分鐘個屁啊,認真看完至少待半個小時。這個我只能說若是你以前已經理解了,那麼畫個10分鐘瞟一眼無所謂的,若是之前沒理解,若是本文能讓你有了更好的理解,那麼花多少時間更無所謂了,要知道懂了java的nio是量的積累,瞭解了其背後的思想和原理是質的積累。並且,我明明計劃半小時寫完的,這會已經2個多小時過去了......框架