什么是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 = position7.重置
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)的物理磁盤中。

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