1.概念
NIO(New Input/Output)和BIO(Blocking Input/Output)是Java中用于處理輸入輸出的兩種不同的模型。
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-698757.html
BIO 會(huì)阻塞,等有了消息,立刻返回,一個(gè)線程處理一個(gè)recv(需要很多線程)。
NIO 有沒(méi)有消息,都返回(但程序要自己判斷,返回空就循環(huán)重復(fù));一個(gè)線程可以處理多個(gè)recv(好處:不用很多線程;壞處:線程空轉(zhuǎn),cpu浪費(fèi)嚴(yán)重)。
?
Java中新的NIO包可以通過(guò)上述形式設(shè)置是否開啟阻塞,從而設(shè)置NIO或BIO,兩者都支持;
?
IO多路復(fù)用
IO多路復(fù)用(IO Multiplexing)是一種通過(guò)單線程處理多個(gè)I/O操作的機(jī)制。它允許一個(gè)進(jìn)程同時(shí)監(jiān)聽多個(gè)文件描述符(如Socket),并在有數(shù)據(jù)可讀或可寫時(shí)進(jìn)行相應(yīng)的處理,從而提高系統(tǒng)的并發(fā)性能。
在傳統(tǒng)的阻塞I/O模型中,每個(gè)I/O操作都需要一個(gè)獨(dú)立的線程來(lái)處理,當(dāng)并發(fā)量增加時(shí),線程數(shù)量會(huì)急劇增加,導(dǎo)致系統(tǒng)資源消耗過(guò)大。而使用IO多路復(fù)用,只需要一個(gè)線程就可以同時(shí)處理多個(gè)I/O操作,大大減少了線程的數(shù)量和系統(tǒng)開銷。
常見的IO多路復(fù)用機(jī)制包括:
-
select:select是Unix系統(tǒng)最早引入的IO多路復(fù)用機(jī)制。它通過(guò)select函數(shù)來(lái)監(jiān)聽多個(gè)文件描述符,當(dāng)其中任意一個(gè)文件描述符準(zhǔn)備就緒時(shí),select函數(shù)會(huì)返回,然后可以通過(guò)遍歷文件描述符集合來(lái)確定哪些文件描述符可讀或可寫。
-
poll:poll是select的一種改進(jìn)版本。它使用一個(gè)pollfd結(jié)構(gòu)體數(shù)組來(lái)管理文件描述符,并通過(guò)poll函數(shù)來(lái)監(jiān)聽多個(gè)文件描述符的狀態(tài)。與select相比,poll沒(méi)有最大文件描述符數(shù)量的限制。
-
epoll:epoll是Linux系統(tǒng)引入的一種高效的IO多路復(fù)用機(jī)制。它使用一個(gè)事件表來(lái)管理文件描述符,并通過(guò)epoll_ctl函數(shù)來(lái)注冊(cè)和刪除事件,通過(guò)epoll_wait函數(shù)來(lái)等待事件的發(fā)生。epoll提供了三種工作模式:邊沿觸發(fā)(EPOLLET)、水平觸發(fā)(EPOLLIN、EPOLLOUT)和一次性觸發(fā)(EPOLLONESHOT),可以根據(jù)具體需求選擇適合的模式。(epoll可以理解為多了個(gè)記事本,)
IO多路復(fù)用適用于處理大量的并發(fā)連接,如服務(wù)器端的網(wǎng)絡(luò)編程。它可以有效地減少線程的數(shù)量,提高系統(tǒng)的并發(fā)性能和資源利用率。
可以說(shuō):
select內(nèi)核無(wú)狀態(tài),每次從零開始
eqoll內(nèi)核維護(hù)一個(gè)狀態(tài),可以異步做很多事情,調(diào)用的時(shí)候能夠立刻給出結(jié)果集
額外拓展
1.epoll機(jī)制詳解
epoll是Linux系統(tǒng)引入的一種高效的IO多路復(fù)用機(jī)制,它提供了一種事件驅(qū)動(dòng)的方式來(lái)處理多個(gè)文件描述符的I/O操作。相比于傳統(tǒng)的select和poll機(jī)制,epoll在處理大量并發(fā)連接時(shí)具有更高的性能。
epoll的核心概念包括以下幾個(gè)部分:
-
epoll實(shí)例(epoll instance):epoll實(shí)例是一個(gè)內(nèi)核數(shù)據(jù)結(jié)構(gòu),用于管理文件描述符和事件。通過(guò)epoll_create函數(shù)來(lái)創(chuàng)建一個(gè)epoll實(shí)例。
-
文件描述符(file descriptor):文件描述符是操作系統(tǒng)對(duì)文件或I/O設(shè)備的引用。在epoll中,需要將需要監(jiān)聽的文件描述符添加到epoll實(shí)例中。
-
事件(event):事件是對(duì)文件描述符的一種狀態(tài)變化的表示,如可讀、可寫等。在epoll中,通過(guò)epoll_event結(jié)構(gòu)體來(lái)表示事件。
-
事件表(event table):事件表是epoll實(shí)例中用來(lái)存儲(chǔ)事件的數(shù)據(jù)結(jié)構(gòu),可以通過(guò)epoll_ctl函數(shù)來(lái)注冊(cè)和刪除事件。
epoll的工作流程如下:
-
創(chuàng)建epoll實(shí)例:通過(guò)epoll_create函數(shù)創(chuàng)建一個(gè)epoll實(shí)例,并返回一個(gè)文件描述符,用于后續(xù)的操作。
-
添加文件描述符:通過(guò)epoll_ctl函數(shù)將需要監(jiān)聽的文件描述符添加到epoll實(shí)例中,并指定需要監(jiān)聽的事件類型。
-
等待事件:通過(guò)epoll_wait函數(shù)等待事件的發(fā)生。當(dāng)有文件描述符的事件發(fā)生時(shí),epoll_wait函數(shù)會(huì)返回,并將事件信息填充到一個(gè)epoll_event數(shù)組中。
-
處理事件:遍歷epoll_event數(shù)組,根據(jù)事件類型進(jìn)行相應(yīng)的處理。
-
循環(huán)操作:重復(fù)執(zhí)行等待事件和處理事件的過(guò)程,實(shí)現(xiàn)持續(xù)的事件驅(qū)動(dòng)。
epoll提供了三種工作模式:
-
邊沿觸發(fā)(EPOLLET):只有在文件描述符狀態(tài)發(fā)生變化時(shí)才觸發(fā)事件,適用于高效處理大量的并發(fā)連接。
-
水平觸發(fā)(EPOLLIN、EPOLLOUT):只要文件描述符處于可讀或可寫狀態(tài),就會(huì)觸發(fā)事件,適用于普通的網(wǎng)絡(luò)編程。
-
一次性觸發(fā)(EPOLLONESHOT):只觸發(fā)一次事件,需要在處理完事件后重新注冊(cè)。
epoll的優(yōu)勢(shì)在于可以處理大量的并發(fā)連接,具有更高的性能和資源利用率。它避免了傳統(tǒng)select和poll機(jī)制中遍歷文件描述符集合的開銷,同時(shí)提供了更靈活的事件觸發(fā)方式。因此,epoll被廣泛應(yīng)用于高性能的網(wǎng)絡(luò)服務(wù)器編程。
2.BIO什么時(shí)候會(huì)阻塞?
BIO(Blocking I/O,阻塞I/O)是一種同步的I/O模型,在進(jìn)行I/O操作時(shí)會(huì)阻塞當(dāng)前線程,直到操作完成或出現(xiàn)錯(cuò)誤。以下情況下,BIO會(huì)發(fā)生阻塞:
-
讀取阻塞:當(dāng)從輸入流(如Socket的InputStream)讀取數(shù)據(jù)時(shí),如果沒(méi)有可讀取的數(shù)據(jù),讀取操作將會(huì)阻塞,直到有數(shù)據(jù)可讀或者發(fā)生超時(shí)或錯(cuò)誤。
-
寫入阻塞:當(dāng)向輸出流(如Socket的OutputStream)寫入數(shù)據(jù)時(shí),如果輸出緩沖區(qū)已滿,寫入操作將會(huì)阻塞,直到有空間可寫或者發(fā)生超時(shí)或錯(cuò)誤。
-
連接阻塞:在使用ServerSocket等待客戶端連接時(shí),accept()方法會(huì)阻塞當(dāng)前線程,直到有客戶端連接成功或發(fā)生超時(shí)或錯(cuò)誤。
BIO的阻塞特性意味著在進(jìn)行I/O操作時(shí),線程會(huì)一直等待,不能處理其他任務(wù)。這可能導(dǎo)致資源浪費(fèi)和性能下降。因此,對(duì)于高并發(fā)的網(wǎng)絡(luò)應(yīng)用,通常使用NIO(Non-blocking I/O,非阻塞I/O)或AIO(Asynchronous I/O,異步I/O)模型來(lái)避免阻塞。
3.上文提到的緩沖區(qū)(詳解)
概念和作用:緩沖區(qū)(Buffer)是在進(jìn)行I/O操作時(shí)用于臨時(shí)存儲(chǔ)數(shù)據(jù)的一塊內(nèi)存區(qū)域。它提供了一種緩沖數(shù)據(jù)的機(jī)制,可以減少實(shí)際的I/O操作次數(shù),提高數(shù)據(jù)讀寫的效率。
在Java中,緩沖區(qū)是通過(guò)Buffer類的實(shí)例來(lái)表示的。Java NIO(New I/O)庫(kù)提供了一組緩沖區(qū)類,如ByteBuffer、CharBuffer、ShortBuffer等,用于處理不同類型的數(shù)據(jù)。
緩沖區(qū)有以下幾個(gè)重要的屬性:
-
容量(Capacity):緩沖區(qū)的容量表示它可以存儲(chǔ)的最大數(shù)據(jù)量。一旦創(chuàng)建,緩沖區(qū)的容量就是固定的,不能改變。
-
位置(Position):緩沖區(qū)的位置表示當(dāng)前讀寫操作的位置。初始時(shí),位置為0,隨著讀寫操作進(jìn)行,位置會(huì)自動(dòng)更新。
-
上界(Limit):緩沖區(qū)的上界表示有效數(shù)據(jù)的末尾位置。讀寫操作不能超過(guò)上界。
-
標(biāo)記(Mark):緩沖區(qū)的標(biāo)記是一個(gè)備忘位置,可以通過(guò)mark()方法設(shè)置,并通過(guò)reset()方法恢復(fù)到標(biāo)記位置。
緩沖區(qū)的基本操作包括:
-
寫入數(shù)據(jù):通過(guò)put()方法將數(shù)據(jù)寫入緩沖區(qū),同時(shí)位置會(huì)自動(dòng)向后移動(dòng)。
-
讀取數(shù)據(jù):通過(guò)get()方法從緩沖區(qū)讀取數(shù)據(jù),同時(shí)位置會(huì)自動(dòng)向后移動(dòng)。
-
翻轉(zhuǎn)緩沖區(qū):通過(guò)flip()方法將上界設(shè)置為當(dāng)前位置,位置重置為0,用于將緩沖區(qū)從寫模式切換到讀模式。
-
清空緩沖區(qū):通過(guò)clear()方法將位置設(shè)置為0,上界設(shè)置為容量,用于將緩沖區(qū)從讀模式切換到寫模式。
緩沖區(qū)的使用可以提高I/O操作的效率,特別是在處理大量數(shù)據(jù)時(shí)。它可以減少系統(tǒng)的調(diào)用次數(shù),提高數(shù)據(jù)讀寫的速度。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-698757.html
?
到了這里,關(guān)于阻塞非阻塞IO(BIO和NIO),IO多路復(fù)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!