成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Java 網(wǎng)絡(luò) IO 模型

Loong_T / 786人閱讀

摘要:有一個(gè)神奇的特性當(dāng)發(fā)起操作之后,線程不用等待讀取完畢,而是可以直接返回,繼續(xù)執(zhí)行其他操作。如果使用,一個(gè)線程可以同時(shí)發(fā)起多個(gè)操作,這就意味著,一個(gè)線程可以同時(shí)處理多個(gè)請(qǐng)求。

在進(jìn)入主題之前先看個(gè) Java 網(wǎng)絡(luò)編程的一個(gè)簡(jiǎn)單例子:代碼很簡(jiǎn)單,客戶(hù)端和服務(wù)端進(jìn)行通信,對(duì)于客戶(hù)端的每次輸入,服務(wù)端回復(fù) get。注意,服務(wù)端可以同時(shí)允許多個(gè)客戶(hù)端連接。

服務(wù)端端代碼:

// 創(chuàng)建服務(wù)端 socket
ServerSocket serverSocket = new ServerSocket(20000);
client = serverSocket.accept();

// 客戶(hù)端連接成功,輸出提示
System.out.println("客戶(hù)端連接成功");
// 啟動(dòng)一個(gè)新的線程處理客戶(hù)端請(qǐng)求
new Thread(new ServerThread(client)).start();


// 子線程中處理客戶(hù)端的輸入
class ServerThread implements Runnable {
    .....
    @Override
    public void run() {
        boolean flag = true;
        while (flag) {

            // 讀取客戶(hù)端發(fā)送來(lái)的數(shù)據(jù)
            String str = buf.readLine();
            
            // 回復(fù)給客戶(hù)端 get 表示收到數(shù)據(jù)
            out.println("get"); 
        }
    }
}

客戶(hù)端代碼 :

Socket client = new Socket("127.0.0.1", 20000);
boolean flag = true;
while (flag) {
    
    // 讀取用戶(hù)從鍵盤(pán)的輸入
    String str = input.readLine();
    // 把用戶(hù)的輸入發(fā)送給服務(wù)端
    out.println(str);

    // 接受到服務(wù)端回傳的 get 字符串
    String echo = buf.readLine();
    System.out.println(echo);
    }
}

考慮到完整的 Java 示例代碼太過(guò)龐大影響閱讀,所以這里不完整貼出,如果需要在 github 直接下載,這里是下載地址。

可以看到,server 為了能夠同時(shí)處理多個(gè) client 的請(qǐng)求,需要為每個(gè) client 開(kāi)啟一個(gè) thread,這種 one-thread-per-client 的模式對(duì)于 server 而言壓力是很大的。假設(shè)有 1k 個(gè) client,對(duì)應(yīng)的 server 應(yīng)該啟動(dòng) 1k 個(gè) thread,那么 server 所耗費(fèi)的內(nèi)存,以及 thread 切換時(shí)候占用的時(shí)間等等都是致命傷。即使使用線程池的技術(shù)來(lái)限制線程個(gè)數(shù),這種 blocking-IO 的模型還是沒(méi)辦法支撐大量連接。

每個(gè) client 都需要一個(gè) thread 來(lái)請(qǐng)求處理。

NIO

上面這種 one-thread-per-client 的模式無(wú)法支撐大量連接的主要原因在于 readLine 會(huì) 阻塞 IO,即在 readLine 沒(méi)能夠讀取到數(shù)據(jù)的時(shí)候,會(huì)一直阻塞線程,使得線程無(wú)法繼續(xù)執(zhí)行,那么 server 為了可以同時(shí)處理多個(gè) client,只能同時(shí)開(kāi)啟多個(gè)線程。

所以,Java 1.4 之后引入了一套 NIO 接口。NIO 中最主要的一個(gè)功能就是可以進(jìn)行非阻塞 IO 操作:如果沒(méi)能夠讀取到數(shù)據(jù),非阻塞 IO 不會(huì)阻塞線程,而是直接返回 0。這種情況下,線程通過(guò)返回值判斷數(shù)據(jù)還沒(méi)有準(zhǔn)備好,就可以處理其他事情,而不會(huì)被阻塞。

上圖是阻塞 IO 和非阻塞 IO 的區(qū)別,可以看出雖然 非阻塞 IO 并不會(huì)被阻塞,但是它仍然不斷的調(diào)用函數(shù)檢查數(shù)據(jù)是否已經(jīng)可讀,這種現(xiàn)象在代碼中是以這種形式展現(xiàn):

while((str = read()) == 0) {
   
}
 // 繼續(xù)讀取到數(shù)據(jù)之后的邏輯。

可以明白,雖然非阻塞 IO 不會(huì)阻塞線程,但是由于沒(méi)有數(shù)據(jù)可讀,線程也沒(méi)有辦法繼續(xù)執(zhí)行下面的邏輯,只能不斷的調(diào)用判斷,等待數(shù)據(jù)到來(lái)。這種情況下稱(chēng)為同步 IO。所以綜上,NIO 本質(zhì)上是一個(gè)非阻塞同步 IO。

IO 復(fù)用

由于 NIO 不會(huì)因?yàn)閿?shù)據(jù)還沒(méi)有到達(dá)而被阻塞,那么就沒(méi)有必要每一個(gè) client 都分配一個(gè) thread 不斷去輪詢(xún)判斷是否有數(shù)據(jù)可讀??梢允褂靡粋€(gè) thread 監(jiān)聽(tīng)所有的 client 連接,由這個(gè) thread 循環(huán)判斷是否有某個(gè) client 的數(shù)據(jù)可讀,如果有就告知其他 thread 某個(gè) client 連接由數(shù)據(jù)可讀。這種行為就被稱(chēng)之為 IO 復(fù)用。 在 NIO 中提供了 Selector 類(lèi)來(lái)監(jiān)聽(tīng)所有 client 連接是否有數(shù)據(jù)可讀。

使用 Selector 來(lái)實(shí)現(xiàn) IO 復(fù)用,只有一個(gè) thread 需要關(guān)心數(shù)據(jù)是否到來(lái),其他線程等待通知就好。如此一來(lái),只有監(jiān)聽(tīng)線程會(huì)一直循環(huán)判斷,并不會(huì)占據(jù)太多 CPU 資源。提到 NIO 中的 Selector,不得不說(shuō)一下 Linux 編程中的 IO 復(fù)用,因?yàn)?NIO 中的 Selector 底層就是使用系統(tǒng)級(jí)的 IO 復(fù)用方案。

Linux 系統(tǒng)的 IO 復(fù)用實(shí)現(xiàn)方案有 2 種:

select

epoll

在 Linux 2.6+ 的版本上 NIO 底層使用的是 epoll,在 2.4.x 的版本使用的是 select 函數(shù)。epoll 函數(shù)在性能方面比 select 好很多,這里可以不關(guān)心 Linux 編程具體細(xì)節(jié)。值得一提的是,Java 的 netty 網(wǎng)絡(luò)框架底層就是使用 NIO 技術(shù)。

AIO

回顧一下 NIO 中:使用監(jiān)聽(tīng)線程調(diào)用 select 函數(shù)來(lái)監(jiān)聽(tīng)所有請(qǐng)求是否有數(shù)據(jù)到達(dá),如果有數(shù)據(jù)則通知其他線程來(lái)讀取數(shù)據(jù)。這里在線程讀取數(shù)據(jù)的過(guò)程中,線程在數(shù)據(jù)沒(méi)有讀取完畢之前是處于阻塞狀態(tài),只有數(shù)據(jù)讀取完畢之后線程才可以繼續(xù)執(zhí)行邏輯。之前說(shuō)過(guò),這種稱(chēng)之為同步 IO。JDK 7 中新增了一套新接口 AIO(Asynchronous IO)。

AIO 有一個(gè)神奇的特性:當(dāng)發(fā)起 IO 操作之后,線程不用等待 IO 讀取完畢,而是可以直接返回,繼續(xù)執(zhí)行其他操作。等到數(shù)據(jù)讀取完畢之后,系統(tǒng)會(huì)通知線程數(shù)據(jù)已經(jīng)讀取完畢。這種發(fā)起 IO 操作,但是不必等待數(shù)據(jù)讀取完畢的 IO 操作稱(chēng)之為異步 IO。如果使用 AIO,一個(gè)線程可以同時(shí)發(fā)起多個(gè) IO 操作,這就意味著,一個(gè)線程可以同時(shí)處理多個(gè)請(qǐng)求。著名的 web 服務(wù)器 Nginx 就是用了異步 IO。關(guān)于更多的細(xì)節(jié),可以參考下我的另一篇文章 End

到目前為止,文章解釋了阻塞/非阻塞 IO,同步/異步 IO 的區(qū)別,談起 IO 模型,不可避免會(huì)涉及 Linux 的 5 種 IO 模型

阻塞 IO

非阻塞 IO

IO 復(fù)用

信號(hào)驅(qū)動(dòng) IO

異步 IO

除去信號(hào)驅(qū)動(dòng) IO沒(méi)有提及,其他 4 種主要的 IO 模型都有所解釋?zhuān)斫饬诉@些 IO 模型的概念對(duì)于編寫(xiě)代碼有很大的幫助。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70605.html

相關(guān)文章

  • java同步非阻塞IO

    摘要:的異步即是異步的,也是非阻塞的。但是,也可以進(jìn)行一層稍微薄點(diǎn)的封裝,保留這種多路復(fù)用的模型,比如的,是一種同步非阻塞的模型。系統(tǒng)調(diào)用操作系統(tǒng)的系統(tǒng)調(diào)用提供了多路復(fù)用的非阻塞的系統(tǒng)調(diào)用,這也是機(jī)制實(shí)現(xiàn)需要用到的。 異步IO編程在javascript中得到了廣泛的應(yīng)用,之前也寫(xiě)過(guò)一篇博文進(jìn)行梳理。js的異步IO即是異步的,也是非阻塞的。非阻塞的IO需要底層操作系統(tǒng)的支持,比如在linux上...

    caoym 評(píng)論0 收藏0
  • JDK10都發(fā)布了,nio你了解多少?

    摘要:而我們現(xiàn)在都已經(jīng)發(fā)布了,的都不知道,這有點(diǎn)說(shuō)不過(guò)去了。而對(duì)一個(gè)的讀寫(xiě)也會(huì)有響應(yīng)的描述符,稱(chēng)為文件描述符,描述符就是一個(gè)數(shù)字,指向內(nèi)核中的一個(gè)結(jié)構(gòu)體文件路徑,數(shù)據(jù)區(qū)等一些屬性。 前言 只有光頭才能變強(qiáng) 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡(jiǎn)單啦 本來(lái)我預(yù)想是先來(lái)回顧一下傳統(tǒng)的IO模式的,將傳統(tǒng)的IO模式的相關(guān)類(lèi)理清楚(因?yàn)镮O的類(lèi)很多)。 但是,發(fā)現(xiàn)在整理的過(guò)程已...

    YFan 評(píng)論0 收藏0
  • Java NIO淺析

    摘要:阻塞請(qǐng)求結(jié)果返回之前,當(dāng)前線程被掛起。也就是說(shuō)在異步中,不會(huì)對(duì)用戶(hù)線程產(chǎn)生任何阻塞。當(dāng)前線程在拿到此次請(qǐng)求結(jié)果的過(guò)程中,可以做其它事情。事實(shí)上,可以只用一個(gè)線程處理所有的通道。 準(zhǔn)備知識(shí) 同步、異步、阻塞、非阻塞 同步和異步說(shuō)的是服務(wù)端消息的通知機(jī)制,阻塞和非阻塞說(shuō)的是客戶(hù)端線程的狀態(tài)。已客戶(hù)端一次網(wǎng)絡(luò)請(qǐng)求為例做簡(jiǎn)單說(shuō)明: 同步同步是指一次請(qǐng)求沒(méi)有得到結(jié)果之前就不返回。 異步請(qǐng)求不會(huì)...

    yeooo 評(píng)論0 收藏0
  • Java網(wǎng)絡(luò)編程-你是GG還是MM?

    摘要:網(wǎng)絡(luò)層主要將從下層接收到的數(shù)據(jù)進(jìn)行地址例的封裝與解封裝。會(huì)話(huà)層通過(guò)傳輸層端口號(hào)傳輸端口與接收端口建立數(shù)據(jù)傳輸?shù)耐贰? 第六階段 網(wǎng)絡(luò)編程 每一臺(tái)計(jì)算機(jī)通過(guò)網(wǎng)絡(luò)連接起來(lái),達(dá)到了數(shù)據(jù)互動(dòng)的效果,而網(wǎng)絡(luò)編程所解決的問(wèn)題就是如何讓程序與程序之間實(shí)現(xiàn)數(shù)據(jù)的通訊與互動(dòng)在嗎?你是GG還是MM? (一) 網(wǎng)絡(luò)模型概述 (1) 兩大模型 網(wǎng)絡(luò)模型一般是指: OSI(Open System Inter...

    Shihira 評(píng)論0 收藏0
  • NIO網(wǎng)絡(luò)相關(guān)基礎(chǔ)知識(shí)

    摘要:操作系統(tǒng)是能夠獲取到事件操作完成的事件,基于回調(diào)函數(shù)機(jī)制和操作系統(tǒng)的操作控制實(shí)現(xiàn)事件檢測(cè)機(jī)制。 前面的文章NIO基礎(chǔ)知識(shí)介紹了Java NIO的一些基本的類(lèi)及功能說(shuō)明,Java NIO是用來(lái)替換java 傳統(tǒng)IO的,NIO的一些新的特性在網(wǎng)絡(luò)交互方面會(huì)更加的明顯。 Java 傳統(tǒng)IO的弊端 ????基于JVM來(lái)實(shí)現(xiàn)每個(gè)通道的輪詢(xún)檢查通道狀態(tài)的方法是可行的,但仍然是有問(wèn)題的,檢查每個(gè)通道...

    1fe1se 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<