Java BIO

引言

Unix網絡編程領域中,IO模型一直是十分重要的話題。而且在去學習RedisNginxNetty等底層原理時,對於高併發的處理,基本都用到了IO模型的概念。java

IO模型分爲阻塞IO、非阻塞IO、多路複用IO、信號驅動IO以及異步IO,本文就其中最基礎的阻塞式IO進行講解。git

BIO

BIOBlocking IO,阻塞IO,對應java.io包。github

Java 1.4以前,提供了java.io包,阻塞IO編程模型。編程

假設咱們須要在Socket(運輸層TCP)的基礎上實現一個HTTP服務器,HTTP服務器網絡編程採用阻塞IO實現,這裏使用經常使用的輸入輸出流BufferedReaderBufferedWriter服務器

請看以下示例代碼,輸入輸出流採用經典的裝飾器模式:網絡

ServerSocket serverSocket = null;
try {
    serverSocket = new ServerSocket(SocketConstant.DEFAULT_PORT);
    System.out.println("服務器啓動於: " + SocketConstant.DEFAULT_PORT);

    while (true) {
        Socket socket = serverSocket.accept();
        System.out.println("客戶端[" + socket.getPort() + "]發起鏈接");

        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

        String msg;
        while ((msg = reader.readLine()) != null) {
            // 處理網絡請求
        }
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    // 回收資源
}

問題出在reader讀取數據時,代碼以下:多線程

String msg;
while ((msg = reader.readLine()) != null) {
    // 處理網絡請求
}

由於採用了阻塞IOBufferedReader進行數據讀取,因此假設網絡擁塞的狀況下,該TCP鏈接遲遲沒有數據發送,線程會一直被阻塞,因示例代碼採用單線程模型,任務變成串行處理,沒法繼續處理其餘請求。併發

因此在BIO條件下,常採用一下編程模型:異步

image.png

爲了保證主線程不被阻塞,服務器能正常接受請求,採用多線程方式解決。socket

主線程Acceptor不負責具體請求的處理,只負責接受請求,並建立相應的Handler線程進行請求處理,全部阻塞發生在Handler線程中,不影響主線程接受其餘任務。

不要在主進程/主線程中處理任務的設計理念是值得學習的,主進程/主線程一旦掛了,整個節點都崩潰了,代價很大。

以下圖所示,Nginx中分爲主進程和工做進程,主進程負責任務分發,工做進程負責任務處理,若是工做進程崩潰了,主進程再從新fork工做進程,進行任務處理,整個節點依然可用。

image.png

根據經典的BIO編程模型,全部請求須要新建Handler線程處理。

new Thread(new Handler(socket)).start();

該模型存在一個致命的問題,當高併發時,形成系統中存在太多的線程,線程運行時的上下文頻繁切換形成額外開銷,給系統形成嚴重負擔。

總結

學院換了副主任,答辯及論文格式規定有所調整,目前還在改格式。

之後會就NIOIO多路複用等經常使用模型進行學習。

版權聲明

本文做者: 河北工業大學夢雲智開發團隊 - 張喜碩
相關文章
相關標籤/搜索