NIO
NIO稱(chēng)為Non-blocking I/O 或 New I/O,就是非阻塞IO或者新IO
BIO網(wǎng)絡(luò)模型
由圖看出BIO每次建立一個(gè)新連接都需要新建一個(gè)線(xiàn)程處理。且隨著線(xiàn)程數(shù)量的增加硬爆,CPU切換線(xiàn)程上下文的消耗也隨之增加。
NIO網(wǎng)絡(luò)模型
而NIO則通過(guò)selector統(tǒng)一接受注冊(cè)事件,再通過(guò)輪循的方式檢測(cè)事件注冊(cè)情況俯树。
NIO核心類(lèi)
Channel:通道
Buffer:緩沖區(qū)(負(fù)責(zé)與通道進(jìn)行通訊)
Selector:選擇器 或 多路復(fù)用器
Channel簡(jiǎn)介
1.Channel負(fù)責(zé)傳輸信息,特點(diǎn)是雙向傳輸丸冕。相比與BIO的流來(lái)說(shuō)流是單向傳輸赠摇。
2.Channe是非阻塞的
3.操作Channel的唯一方式是Buffer超燃。
Channel代碼操作
// 代碼片段 1:服務(wù)器端通過(guò)服務(wù)器socket創(chuàng)建channel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 代碼片段 2:服務(wù)器端綁定端口
serverSocketChannel.bind(new InetSocketAddress(8000));
// 代碼片段 3:服務(wù)器端監(jiān)聽(tīng)客戶(hù)端連接区拳,建立socketChannel連接
SocketChannel socketChannel = serverSocketChannel.accept();
// 代買(mǎi)片段 4:客戶(hù)端連接遠(yuǎn)程主機(jī)及端口
SocketChannel socketChannel = SocketChannel.open(
new InetSocketAddress("127.0.0.1", 8000))
Buffer簡(jiǎn)介
? 提供唯一與Channel進(jìn)行交互的方式拘领。
作用:讀寫(xiě)Channel中的數(shù)據(jù)
本質(zhì):一塊可以從中讀取或?qū)懭氲膬?nèi)存區(qū)域意乓。被NIO包裝成一個(gè)NIO Buffer對(duì)象,并提供一組便于操作內(nèi)存的方法。
Buffer屬性
(1)Capacity:容量届良。
標(biāo)明數(shù)組可以容納的最大字節(jié)長(zhǎng)度笆凌,若超出容量,則需要將其清空后才能重新寫(xiě)入士葫。
(2)Position:位置
寫(xiě)模式:表示當(dāng)前的位置乞而,初始位置為0,最大值為 Capacity-1
讀模式:重置為0
(3)Limit:上限
寫(xiě)模式:最多能往Buffer中寫(xiě)的數(shù)據(jù)數(shù)量慢显,此時(shí)等于Capacity
讀模式:此時(shí)等于寫(xiě)模式下的Position值爪模。
(4)Mark:標(biāo)記
標(biāo)記一個(gè)特定Position位置,可通過(guò)Buffer的Reset()方法恢復(fù)到標(biāo)記位置荚藻。
Buffer使用
// 初始化長(zhǎng)度為10的byte類(lèi)型Buffer
ByteBuffer.allocate(10);
// 向byteBuffer中寫(xiě)入三個(gè)字節(jié)
byteBuffer.put("abc".getBytes(Charset.forName("UTF-8")));
// 將byteBuffer從寫(xiě)模式切換成讀模式
byteBuffer.flip();
// 從byteBuffer中讀取一個(gè)字節(jié)
byteBuffer.get();
// 調(diào)用mark方法記錄下當(dāng)前position的位置
byteBuffer.mark();
// 先調(diào)用get方法讀取下一個(gè)字節(jié)
byteBuffer.get()
// 再調(diào)用reset()方法將position重置到mark位置
byteBuffer.reset()
// 調(diào)用clear方法屋灌,將所有屬性重置
byteBuffer.clear()
Selector簡(jiǎn)介
負(fù)責(zé)處理所有的客戶(hù)端注冊(cè),管理多個(gè)Channel应狱。
Selector使用
// 代碼片段 1:創(chuàng)建Selector
Selector selector = Selector.open();
// 代碼片段 2:將channel注冊(cè)到selector上共郭,監(jiān)聽(tīng)讀就緒事件
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_READ);
// 代碼片段 3:阻塞等待channel的就緒事件發(fā)生
int selectNum = selector.select();
// 代碼片段 4:獲取發(fā)生就緒事件的channel集合
Set<SelectionKey> selectedKeys = selector.selectedKeys();
SelectionKey簡(jiǎn)介
(1)四種就緒狀態(tài)常量
SelectionKey常量提供了四個(gè)可監(jiān)聽(tīng)事件的靜態(tài)常量值。
OP_CONNECT:連接就緒疾呻。連接操作除嘹,Client端支持的一種操作
OP_ACCEPT:接收就緒。連接可接受操作岸蜗,僅ServerSocketChannel支持
OP_READ:讀就緒尉咕。
OP_WRITE:寫(xiě)就緒。
(2)可以獲取有價(jià)值的屬性
在調(diào)用Selector對(duì)象的SelectedKey方法時(shí)璃岳,會(huì)返回一個(gè)SelectionKey的集合龙考。可以通過(guò)這個(gè)SelectionKey的集合獲取當(dāng)前的Channel矾睦、當(dāng)前Selector的對(duì)象晦款、Channel已就緒事件集合和所關(guān)心事件集合。
ps:本文大部分內(nèi)容參考于https://blog.csdn.net/qq_28303495/article/details/89514690枚冗,他寫(xiě)的比我更加詳細(xì)缓溅,此文只為自己學(xué)習(xí)作一個(gè)總結(jié)。