1. 程式人生 > >java NIO理解分析與基本使用

java NIO理解分析與基本使用

我前段時間的一篇部落格[java網路程式設計——多執行緒資料收發並行](https://www.cnblogs.com/buptleida/p/12514450.html)總結了服務端與客戶端之間的收發並行實踐。原理很簡單,就是針對單一客戶端,服務端起兩個執行緒分別負責read和write操作,然後執行緒保持阻塞等待讀寫執行。 事實上,這樣的模式非常糟糕。因為每一個客戶端在服務端需要佔用兩條執行緒,假如有1000個客戶端,則需要2000+條執行緒。cpu需要花費大量的時間進行執行緒上下文切換,造成系統資源浪費。 想要縮減執行緒數量,先要解決阻塞問題。而NIO可以通過IO多路複用將read和write的阻塞給抹去。再配合執行緒池,即可實現用少量的執行緒支撐起上百萬個客戶端的連線。 ## 什麼是NIO #### NIO與IO多路複用 java NIO全稱java non-blocking IO。字面意思即非阻塞式IO。實際上這裡的非阻塞只是巨集觀的說法。 關於IO模式,這裡引一個別人的部落格,介紹了幾種IO模式的區別: [簡述同步IO、非同步IO、阻塞IO、非阻塞IO之間的聯絡與區別](https://www.cnblogs.com/felixzh/p/10345929.html) 本部落格不再贅述這些,只是想說NIO屬於其中的IO複用模型。(實驗室裡有一本《UNIX網路程式設計》疫情結束回學校一定把這部分好好看看) 多路複用IO模型中,會有一個執行緒去不斷輪詢多個socket的狀態,當socket有讀寫事件時,才來呼叫IO操作。因為是一個執行緒來管理多個socket,系統不需要建立其它執行緒、維護執行緒,只有socket就緒時,才會使用IO資源,所以它大大降低了資源佔用。 java NIO中,使用selector.select()監聽多個通道是否有到達事件,沒有事件就一直阻塞,有事件就呼叫IO進行處理。 #### 三大核心 - 通道(Channel) - 緩衝區(Buffer) - 選擇器(Selectors) 詳細介紹如下 ![image](http://qiniu.debrisflow.cn/20200404NIO3Bean.png) ## NIO使用舉例 這裡以服務端讀取客戶端訊息的流程為例,介紹NIO的使用(完整內容只有輸入,暫且不管輸出)。畫了一個流程圖,如下所示: ![image](http://qiniu.debrisflow.cn/20200404NIORead.png) 1. 建立selector和ServerSocketChannel,並繫結註冊,用於監聽客戶端連線請求,程式碼如下: ``` selector = Selector.open(); ServerSocketChannel server = ServerSocketChannel.open(); // 設定為非阻塞 server.configureBlocking(false); // 繫結本地埠 server.socket().bind(new InetSocketAddress(port)); // 註冊客戶端連線到達監聽 server.register(selector, SelectionKey.OP_ACCEPT); ``` 同時還要建立readSelector和writeSelector。其實執行緒池也是提前建立的,這裡暫且不寫。 ``` readSelector = Selector.open(); writeSelector = Selector.open(); ``` 2. 監聽通道,得到客戶端,並建立SocketChannel,用於監聽後續客戶端訊息 ``` //select()方法返回已就緒的通道數 if (selector.select() == 0) { continue; }