Java NIO(New IO)是一個可以替代標(biāo)準(zhǔn)Java IO API的IO API(從Java 1.4開始)吕嘀,Java NIO提供了與標(biāo)準(zhǔn)IO不同的IO工作方式。
Java NIO: Channels and Buffers(通道和緩沖區(qū))
標(biāo)準(zhǔn)的IO基于字節(jié)流和字符流進(jìn)行操作的沮峡,而NIO是基于通道(Channel)和緩沖區(qū)(Buffer)進(jìn)行操作,數(shù)據(jù)總是從通道讀取到緩沖區(qū)中,或者從緩沖區(qū)寫入到通道中眉厨。
Java NIO: Non-blocking IO(非阻塞IO)
Java NIO可以讓你非阻塞的使用IO喊式,例如:當(dāng)線程從通道讀取數(shù)據(jù)到緩沖區(qū)時孵户,線程還是可以進(jìn)行其他事情。當(dāng)數(shù)據(jù)被寫入到緩沖區(qū)時岔留,線程可以繼續(xù)處理它夏哭。從緩沖區(qū)寫入通道也類似。
Java NIO: Selectors(選擇器)
Java NIO引入了選擇器的概念献联,選擇器用于監(jiān)聽多個通道的事件(比如:連接打開竖配,數(shù)據(jù)到達(dá))。因此里逆,單個的線程可以監(jiān)聽多個數(shù)據(jù)通道进胯。
Java NIO 由以下幾個核心部分組成:
- Channels
- Buffers
- Selectors
基本上,所有的 IO 在NIO 中都從一個Channel 開始原押。Channel 有點象流胁镐。 數(shù)據(jù)可以從Channel讀到Buffer中,也可以從Buffer 寫到Channel中班眯。
Channel通道涵蓋了UDP 和 TCP 網(wǎng)絡(luò)IO希停,以及文件IO
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
Buffer實現(xiàn),覆蓋了能通過IO發(fā)送的基本數(shù)據(jù)類型:byte, short, int, long, float, double
和 char
署隘。
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
Selector允許單線程處理多個 Channel宠能。如果你的應(yīng)用打開了多個連接(通道),但每個連接的流量都很低磁餐,使用Selector就會很方便违崇。例如阿弃,在一個聊天服務(wù)器中。
一羞延、NIO的使用
1.Channel
FileChannel
從文件中讀寫數(shù)據(jù)渣淳。
DatagramChannel
能通過UDP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)。
SocketChannel
能通過TCP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)伴箩。
ServerSocketChannel
可以監(jiān)聽新進(jìn)來的TCP連接入愧,像Web服務(wù)器那樣。對每一個新進(jìn)來的連接都會創(chuàng)建一個SocketChannel
嗤谚。
使用FileChannel
讀取數(shù)據(jù)到Buffer中的示例:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
System.out.println("Read " + bytesRead);
buf.flip();
while(buf.hasRemaining()){
System.out.print((char) buf.get());
}
buf.clear();
bytesRead = inChannel.read(buf);
}
aFile.close();
2.Buffer的使用
使用Buffer一般遵循下面幾個步驟:
- 分配空間(
ByteBuffer buf = ByteBuffer.allocate(1024);
還有一種allocateDirector) - 寫入數(shù)據(jù)到Buffer(
int bytesRead = fileChannel.read(buf);
) - 調(diào)用
filp()
方法(buf.flip();
) - 從Buffer中讀取數(shù)據(jù)(
System.out.print((char)buf.get());
) - 調(diào)用
clear()
方法或者compact()
方法
Buffer顧名思義:緩沖區(qū)棺蛛,實際上是一個容器,一個連續(xù)數(shù)組巩步。Channel提供從文件旁赊、網(wǎng)絡(luò)讀取數(shù)據(jù)的渠道,但是讀寫的數(shù)據(jù)都必須經(jīng)過Buffer椅野。如下圖:
向Buffer中寫數(shù)據(jù):
- 從Channel寫到Buffer (
fileChannel.read(buf)
) - 通過Buffer的
put()
方法 (buf.put(…)
)
從Buffer中讀取數(shù)據(jù):
- 從Buffer讀取到Channel (
channel.write(buf)
) - 使用
get()
方法從Buffer中讀取數(shù)據(jù) (buf.get()
)
可以把Buffer簡單地理解為一組基本數(shù)據(jù)類型的元素列表终畅,它通過幾個變量來保存這個數(shù)據(jù)的當(dāng)前位置狀態(tài):capacity, position, limit, mark
3.Selector
Selector的創(chuàng)建:
Selector selector = Selector.open();
為了將Channel和Selector配合使用,必須將Channel注冊到Selector上竟闪,通過SelectableChannel.register()方法來實現(xiàn):
ssc= ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(PORT));
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);