NIO與IO

NIO與IO

1、阻塞IO實例:

    public void serve(int portNumber) throws IOException {
        //創(chuàng)建一個新的 ServerSocket祥楣,用以監(jiān)聽指定端口上的連接請求
        ServerSocket serverSocket = new ServerSocket(portNumber);
        //對accept()方法的調(diào)用將被阻塞开财,直到一個連接建立
        Socket clientSocket = serverSocket.accept();
        //這些流對象都派生于該套接字的流對象汉柒,創(chuàng)建一個緩沖區(qū)存儲輸入流
        BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
        PrintWriter out =
                new PrintWriter(clientSocket.getOutputStream(), true);
        String request, response;
        //處理循環(huán)開始
        while ((request = in.readLine()) != null) {
            if ("Done".equals(request)) {
                break;
            }
            //請求被傳遞給服務(wù)器的處理方法
            response = processRequest(request);
            //服務(wù)器的響應(yīng)被發(fā)送給了客戶端
            out.println(response);
            //繼續(xù)執(zhí)行處理循環(huán)
        }
    }

    private String processRequest(String request){
        return "Processed";
    }

上面的實例只能同時處理一個連接,要管理多個并發(fā)客戶端责鳍,需要為每個新的客戶端socket創(chuàng)建一個新的Thread碾褂,如下圖:


image.png

這種方案的影響:
①在任何時候都可能有大量的線程處于休眠狀態(tài),只是等待輸入或者輸出數(shù)據(jù)就緒历葛,這可能算是一種資源浪費正塌。
②需要為每個線程的調(diào)用棧都分配內(nèi)存,其默認值大小區(qū)間為64 KB到1 MB啃洋,具體取決于操作系統(tǒng)传货。
③即使Java虛擬機(JVM)在物理上可以支持非常大數(shù)量的線程屎鳍,但是遠在到達該極限之前宏娄,上下文切換所帶來的開銷就會帶來麻煩,例如逮壁,在達到10 000個連接的時候孵坚。

雖然這種并發(fā)方案對于支撐中小數(shù)量的客戶端來說還算可以接受,但是為了支撐100 000或者更多的并發(fā)連接所需要的資源使得它很不理想

2窥淆、NIO
非阻塞設(shè)計卖宠,其實際上消除了IO的那些弊端。
實例:

public void serve(int port) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        ServerSocket ss = serverChannel.socket();
        InetSocketAddress address = new InetSocketAddress(port);
        //將服務(wù)器綁定到選定的端口
        ss.bind(address);
        //打開Selector來處理 Channel
        Selector selector = Selector.open();
        //將ServerSocket注冊到Selector以接受連接
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
        for (;;){
            try {
                //等待需要處理的新事件忧饭;阻塞將一直持續(xù)到下一個傳入事件
                selector.select();
            } catch (IOException ex) {
                ex.printStackTrace();
                //handle exception
                break;
            }
            //獲取所有接收事件的SelectionKey實例
            Set<SelectionKey> readyKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                try {
                    //檢查事件是否是一個新的已經(jīng)就緒可以被接受的連接
                    if (key.isAcceptable()) {
                        ServerSocketChannel server =
                                (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        client.configureBlocking(false);
                        //接受客戶端扛伍,并將它注冊到選擇器
                        client.register(selector, SelectionKey.OP_WRITE |
                                SelectionKey.OP_READ, msg.duplicate());
                        System.out.println(
                                "Accepted connection from " + client);
                    }
                    //檢查套接字是否已經(jīng)準(zhǔn)備好寫數(shù)據(jù)
                    if (key.isWritable()) {
                        SocketChannel client =
                                (SocketChannel) key.channel();
                        ByteBuffer buffer =
                                (ByteBuffer) key.attachment();
                        while (buffer.hasRemaining()) {
                            //將數(shù)據(jù)寫到已連接的客戶端
                            if (client.write(buffer) == 0) {
                                break;
                            }
                        }
                        //關(guān)閉連接
                        client.close();
                    }
                } catch (IOException ex) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException cex) {
                        // ignore on close
                    }
                }
            }
        }
    }
image.png

圖1-2 使用Selector的非阻塞I/O

class java.nio.channels.Selector是Java的非阻塞I/O實現(xiàn)的關(guān)鍵。它使用了事件通知API以確定在一組非阻塞套接字中有哪些已經(jīng)就緒能夠進行I/O相關(guān)的操作词裤。因為可以在任何的時間檢查任意的讀操作或者寫操作的完成狀態(tài)刺洒,所以如圖1-2所示,一個單一的線程便可以處理多個并發(fā)的連接吼砂。

總體來看逆航,與阻塞I/O模型相比,這種模型提供了更好的資源管理:

使用較少的線程便可以處理許多連接渔肩,因此也減少了內(nèi)存管理和上下文切換所帶來開銷因俐;
當(dāng)沒有I/O操作需要處理的時候,線程也可以被用于其他任務(wù)周偎。
盡管已經(jīng)有許多直接使用Java NIO API的應(yīng)用程序被構(gòu)建了抹剩,但是要做到如此正確和安全并不容易。特別是蓉坎,在高負載下可靠和高效地處理和調(diào)度I/O操作是一項繁瑣而且容易出錯的任務(wù)

參考:《Netty in Action》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末澳眷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子袍嬉,更是在濱河造成了極大的恐慌境蔼,老刑警劉巖灶平,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異箍土,居然都是意外死亡逢享,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門吴藻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞒爬,“玉大人,你說我怎么就攤上這事沟堡〔嗟” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵航罗,是天一觀的道長禀横。 經(jīng)常有香客問我,道長粥血,這世上最難降的妖魔是什么柏锄? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮复亏,結(jié)果婚禮上趾娃,老公的妹妹穿的比我還像新娘。我一直安慰自己缔御,他們只是感情好抬闷,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耕突,像睡著了一般笤成。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上有勾,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天疹启,我揣著相機與錄音,去河邊找鬼蔼卡。 笑死喊崖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的雇逞。 我是一名探鬼主播荤懂,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼塘砸!你這毒婦竟也來了节仿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤掉蔬,失蹤者是張志新(化名)和其女友劉穎廊宪,沒想到半個月后矾瘾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡箭启,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年壕翩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傅寡。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡放妈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荐操,到底是詐尸還是另有隱情芜抒,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布托启,位于F島的核電站宅倒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏驾中。R本人自食惡果不足惜唉堪,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肩民。 院中可真熱鬧,春花似錦链方、人聲如沸持痰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽工窍。三九已至,卻和暖如春前酿,著一層夾襖步出監(jiān)牢的瞬間患雏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工罢维, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淹仑,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓肺孵,卻偏偏與公主長得像匀借,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子平窘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容