国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

java十分鐘速懂知識點——NIO

2019-11-14 14:58:45
字體:
來源:轉載
供稿:網友

一、引子

    nio是java的IO框架里邊十分重要的一部分內容,其最核心的就是提供了非阻塞IO的處理方式,最典型的應用場景就是處理網絡連接。很多同學提起nio都能說起一二,但是細究其背后的原理、思想往往就開始背書,說來說去都是那么幾句,其中不少人并不見的真的很理解。本人之前就屬于此類,看了很多書和博客,但是大多數都只是講了三件套和怎么使用,很少會很細致的講背后的思想,那本次我們就來扒一扒吧。
    很多博客描述nio都是這么說的:基于Reactor模式實現的多路非阻塞高性能的網絡IO。那么我們就從這個定義來分析,其中兩個關鍵點:多路非阻塞和Reactor模式。(本來想把高性能也算進去,但是后來想想這個應該算前兩者的結果)下邊我們來分別搞懂這兩塊。

二、網絡IO模型

    多路非阻塞其實準確的名字叫做IO多路復用模型,其是linux五種網絡模型之一,也是當前網絡編程最常使用的模型之一。至于詳細的介紹請參考博客:高性能IO模型淺析(這個里邊只給出了4中,沒有信號驅動IO,但講的很贊,特別是圖),這里僅作簡要介紹和對比:

  • 阻塞IO:java中老的bio便是這種模式,在接到事件(數據到達、數據拷貝完成等)前程序需阻塞等待。優點是編碼簡單,缺點是效率低,處理程序阻塞會導致cpu利用率很低。
  • 非阻塞IO:在未接到事件時處理程序一直主動輪詢,這樣處理程序無需阻塞,可以在輪詢間歇去干別的,但是輪詢會造成重復請求,同樣浪費資源。以前java中實現的的偽異步模式就是采用這種思想。
  • IO復用模型:增加了對socket的事件監聽器(selector),從而把處理程序和對應的socket事件解耦,所用的socket連接都注冊在監聽器,在等待階段只有監聽器會阻塞,處理線程從監聽器獲取事件對socket連接處理即可,而且一個處理線程可以對應多個連接(前兩種一般都是一個socket連接起一個線程,這就是為什么叫復用),有點是節省資源,由于處理程序能夠被多個連接復用,因此少數的線程就能處理大量連接。缺點同樣因為復用,如果是大量費時處理的連接(如大量連接上傳大文件),很容易造成線程占滿而導致新連接失敗。
  • 信號驅動IO模型:在數據準別階段無需阻塞,只需向系統注冊一個信號,在數據準備好后,系統會響應該信號。該模型依賴于系統實現,而且信號通信使用比較麻煩,因此java中未有對應實現。
  • 異步IO:與信號驅動IO很類似,而且在數據拷貝階段(指數據從系統緩沖區拷貝至程序自己的緩沖區,其他模型改階段程序都需要阻塞等待)同樣可以異步處理。有點不必多說,效率很高,缺點是依賴系統底層實現。目前很多語言都提供該模型的實現,jdk1.7之后同樣在concurrent包中提供了。

    對比以上五種模型可以知道,IO復用模型從效率和實現成本綜合而言目前是比較好的選擇,這就是java基于該模型實現nio的根本原因。上邊提到了IO復用模型的實現思想,其實這種思想在其他語言中早已實現(如C++中據說流弊哄哄超10w行代碼的ACE,自適配通信環境,就采用了該模型),并且提出了一個叫Reactor的設計模式。

三、Reactor模

    Reactor模式,翻譯過來叫做反引器模式,其目的是在事件驅動的應用中,將一個請求的能夠分離并且調度給應用程序。我相信大多數人都沒看明白前一句的意思(書還是要背的),說白了就是對于一個請求的多個事件(如連接、讀寫等),經過這種模式的處理,能夠區分出來,并且分別交給對應的處理模塊處理。廢話不多說,來看下一個簡圖:

    可以看到Reactor模式中組件有acceptor、dispatcher和handler(這里只是拿一種實現做個例子,真實的實現各有不同),其中acceptor中注冊了各類事件,當連接有新的事件過來時,其會將事件交給dispatcher進行分發;dispatcher綁定了事件和對應處理程序handler的映射關系,當接到新事件時其會把事件分發到對應handler;而handler負責處理對應事件,這塊就是我們的業務層了。
    從該模式我們可以發現,對于acceptor、dispatcher我們往往只需要一個線程作為入口即可,因為其并不會有耗時處理,效率很高,而handler則根據需要起幾個線程即可(多數時候使用一個線程池實現),這正是IO復用模型望的效果。
    下邊我們會介紹NIO是如何實現該模式的,在此之前先介紹一下框架,其實除了NIO之外,基于JVM實現的還有其他Reactor框架,正好最近OSC牽頭翻譯了對應文檔,有興趣的可以看下:Reactor 指南

四、NIO

    NIO的細節就不多講了,這里只介紹下三件套:
  • channel:管道,可以看做對流的封裝,有點像pipe,不過其是全雙工的。其好處是屏蔽了底層細節,不用關心流對應的是文件還是網絡,也不用關心連接怎么處理的,而且全雙工,不用考慮輸入流或輸出流,你只用使用buffer對其進行讀寫就行了。
  • buffer:channel的好基友,底層就是個字節數組,不同的是對其進行了封裝,不僅提供了對基本類型的支持,而且內部維持了讀寫位置(postion、limit、capacity、mark等),還提供了便捷的方法(clear、flip)。對channel的讀寫必須通過buffer。
  • selector:這個不多說了,如果前邊認真看基本上就明白干啥的,就是Reactor模式中Acceptor的實現。

    再來看個簡圖吧:

    基本上和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做對應處理    }}
View Code

六、最后一點啰嗦

    我想如果這會兒還有人記得標題一定會罵我了,丫的十分鐘個屁啊,認真看完至少待半個小時。這個我只能說如果你之前已經理解了,那么畫個10分鐘瞟一眼無所謂的,如果以前沒理解,如果本文能讓你有了更好的理解,那么花多少時間更無所謂了,要知道懂了java的nio是量的積累,了解了其背后的思想和原理是質的積累。而且,我明明計劃半小時寫完的,這會已經2個多小時過去了......


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 赣榆县| 伽师县| 洛南县| 安义县| 肃北| 南江县| 江油市| 嫩江县| 女性| 马鞍山市| 盐边县| 扎赉特旗| 华亭县| 阜新市| 定远县| 合作市| 平和县| 团风县| 贵阳市| 芦山县| 衡南县| 秀山| 灵石县| 正镶白旗| 瓮安县| 平塘县| 英超| 广灵县| 黄浦区| 陈巴尔虎旗| 洪雅县| 资阳市| 兴安县| 英吉沙县| 建昌县| 城步| 延津县| 鲁甸县| 商南县| 上犹县| 柘荣县|