NIO

什么是NIO?

NIO 全程 java non-blocking IO,是指jdk1.4 提供的新api(NEW IO)

NIO與IO的區(qū)別

NIO 特點(diǎn):非阻塞,面向緩沖區(qū)
IO 特點(diǎn):阻塞式,面向流

阻塞與非阻塞

java io 是阻塞式的,當(dāng)一個(gè)線程調(diào)用read 或者write方法后開始阻塞,直到讀取到數(shù)據(jù)或者寫入數(shù)據(jù)完成,該線程一直處于阻塞狀態(tài)不能做其他事情。
java nio 通過選擇器實(shí)現(xiàn)非阻塞式IO,通過一個(gè)專門的選擇器線程來監(jiān)視 讀請(qǐng)求或者寫請(qǐng)求是否已經(jīng)具備完整條件。
非阻塞讀:如某個(gè)線程發(fā)送一個(gè)讀請(qǐng)求,則它只能獲取到當(dāng)前可用的數(shù)據(jù),如果沒有可用的數(shù)據(jù)直接返回,而不是阻塞在這里,直到數(shù)據(jù)變得可讀取。在數(shù)據(jù)變得可讀取之前該線程是可以繼續(xù)處理其他任務(wù)的。
非阻塞寫:如某個(gè)線程發(fā)送寫請(qǐng)求,需要寫一些數(shù)據(jù)到通道中,但不需要等到將所有數(shù)據(jù)都完全寫入,該線程可以同時(shí)做其他任務(wù)。
線程通常將非阻塞的IO的空閑時(shí)間用來執(zhí)行其他通道的IO任務(wù),所以一個(gè)單獨(dú)的線程可以管理多個(gè)輸入和輸出通道。

NIO重要屬性

Channel

通道:channel 是在rt.jar java.util.nio 包下定義的,表示io源與目標(biāo)打開的鏈接。
通道不能直接傳輸數(shù)據(jù)只能配合緩沖區(qū)使用。
通道類似于流 ,但是通道是雙向的,即可以將通道指向的目標(biāo)源數(shù)據(jù)讀入到緩沖區(qū),也可以將緩沖區(qū)數(shù)據(jù)寫入到鏈接通道的目標(biāo)源。通道好比是鐵路,緩沖區(qū)為火車,火車載人,通過鐵路來運(yùn)輸。
主要方法
將通道指向的目標(biāo)源讀到dst緩沖區(qū)中
將數(shù)據(jù)寫入目標(biāo)源:
java.nio.channels.SeekableByteChannel#read(ByteBuffer dst)

向通道指向的目標(biāo)源寫入數(shù)據(jù)
java.nio.channels.SeekableByteChannel#write(ByteBuffer dst)

Buffer

緩沖區(qū)是存儲(chǔ)數(shù)據(jù)的數(shù)組
重要屬性
1 capacity:緩沖區(qū)容量大小,一旦創(chuàng)建不可改變
2 limit:緩沖區(qū)可用數(shù)據(jù)大小,也就是緩沖區(qū)最后一個(gè)可操作數(shù)據(jù)的下標(biāo),該下標(biāo)之后的緩沖區(qū)數(shù)據(jù)不可操作。小于等于capacity
3 position:當(dāng)前操作的位置。小于等于limit
4 mark:上一次標(biāo)記的索引位置
重要方法

  • 1.向緩沖區(qū)寫入數(shù)組

put(byte[] src, int offset, int length)
src:要寫入的數(shù)據(jù)
offset:寫入數(shù)據(jù)src的開始下標(biāo)(從src的offset位置開始)
length:寫入數(shù)據(jù)的長(zhǎng)度

將src數(shù)組中下標(biāo)位置從offset開始到長(zhǎng)度為length的數(shù)據(jù)防在緩沖區(qū)中。

注意: offset指從數(shù)組的offset下標(biāo)開始獲取數(shù)據(jù)

  • 2.將緩沖區(qū)數(shù)據(jù)讀到數(shù)組中

get(byte[] dst, int offset, int length)
src:dst數(shù)組開始下標(biāo)
length:讀取數(shù)據(jù)的長(zhǎng)度

將緩沖區(qū)中的數(shù)據(jù)讀取到byte數(shù)組中,數(shù)組從索引為 offset位置開始存入length長(zhǎng)度的數(shù)據(jù)

注意: offset指數(shù)組的offset下標(biāo)開始

  • 3.切換讀模式
    filp()
    緩沖區(qū)從寫模式切換到讀模式。此時(shí)position = 0,limit = 寫入數(shù)據(jù)的最大長(zhǎng)度(最后一次寫操作的position),mark=-1 標(biāo)記位清空

  • 4.重讀
    rewind()
    緩沖區(qū)的數(shù)據(jù)需要再次讀取
    position=0,limit不變,mark=-1

  • 5.清除緩沖區(qū)
    clear()
    清除緩沖區(qū),此時(shí)將所有屬性恢復(fù),position=0,limit=capacity,但是緩沖區(qū)數(shù)據(jù)沒有刪除。這些數(shù)據(jù)成為被遺忘的數(shù)據(jù)。(可以通過設(shè)置position于limit來)

  • 6.標(biāo)記
    mark()
    標(biāo)記當(dāng)前位置 mark = position

  • 7.重置
    reset()
    position=mark

Selector

選擇器 ,它是Java NIO核心組件中的一個(gè),用于檢查一個(gè)或多個(gè)NIO Channel(通道)的狀態(tài)是否處于可讀、可寫。
使用Selector的好處在于: 使用更少的線程來就可以來處理通道了, 相比使用多個(gè)線程,避免了線程上下文切換帶來的開銷。
示例代碼:
Selector selector = Selector.open(); channel.configureBlocking(false); SelectionKey key = channel.register(selector, Selectionkey.OP_READ);
channel.configureBlocking(false);
將通道設(shè)置為非阻塞式,F(xiàn)ileChannel 是阻塞式的不能使用選擇器,SocketChannel 網(wǎng)絡(luò)套接字的通道可以設(shè)置為非阻塞式。

register方法的第二個(gè)參數(shù)是監(jiān)聽事件的類型。選擇器可以監(jiān)聽以下四種類型的事件
Connect :鏈接就 SelectionKey.OP_CONNECT
Accept:接收就緒 SelectionKey.OP_ACCEPT
Read:讀就緒 SelectionKey.OP_READ
Write:寫就緒 SelectionKey.OP_WRITE

如果需要注冊(cè)多個(gè)事件
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

可以通過以下方法來確定以上事件是否準(zhǔn)備就緒,它們都會(huì)返回一個(gè)布爾類型:
鏈接就緒:selectionKey.isConnectable();
接收就緒:selectionKey.isAcceptable();
讀就緒:selectionKey.isReadable();
寫就緒:selectionKey.isWritable();

Set selectedKeys =selector.selectedKeys();

Iterator keyIterator = selectedKeys.iterator();

while(keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();
    if(key.isAcceptable()) {
        // a connection was accepted by a ServerSocketChannel.
    } else if (key.isConnectable()) {
        // a connection was established with a remote server.
    } else if (key.isReadable()) {
        // a channel is ready for reading
    } else if (key.isWritable()) {
        // a channel is ready for writing
    }
    keyIterator.remove();
}

直接緩沖區(qū)與非直接緩沖區(qū)

非直接緩沖區(qū)

客戶端向服務(wù)端發(fā)送數(shù)據(jù),先將數(shù)據(jù)發(fā)送到虛擬機(jī)中用戶地址中空間的緩存中,然后用戶地址空間將數(shù)據(jù)復(fù)制到系統(tǒng)內(nèi)核地址空間的緩存中,內(nèi)核地址空間將數(shù)據(jù)寫入到系統(tǒng)的物理磁盤中。

image.png

直接緩沖區(qū)

直接緩沖區(qū)省去了用戶地址空間緩存到內(nèi)核地址空間緩存的復(fù)制過程,用物理內(nèi)存映射文件來代替,直接將數(shù)據(jù)存入到物理內(nèi)存中,然后在將數(shù)據(jù)存入到物理磁盤中。
可以通過Buffer.allocateDirect 方法來創(chuàng)建直接緩沖區(qū)。


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)自 http://www.ibm.com/developerworks/cn/education/java/j-...
    抓兔子的貓閱讀 2,494評(píng)論 0 22
  • # Java NIO # Java NIO屬于非阻塞IO,這是與傳統(tǒng)IO最本質(zhì)的區(qū)別。傳統(tǒng)IO包括socket和文...
    Teddy_b閱讀 721評(píng)論 0 0
  • Java NIO(New IO)是從Java 1.4版本開始引入的一個(gè)新的IO API,可以替代標(biāo)準(zhǔn)的Java I...
    JackChen1024閱讀 7,944評(píng)論 1 143
  • JAVA NIO基礎(chǔ) ...
    文思li閱讀 684評(píng)論 0 3
  • NIO概述 Java NIO全稱為Non-blocking IO或者New IO,從名字我們知道NIO是非阻塞的I...
    zhong0316閱讀 755評(píng)論 0 7

友情鏈接更多精彩內(nèi)容