NIO主要有三大核心部分:Channel(通道),Buffer(緩沖區(qū)), Selector。傳統(tǒng)IO基于字節(jié)流和字符流進(jìn)行操作,而NIO基于Channel和Buffer(緩沖區(qū))進(jìn)行操作,數(shù)據(jù)總是從通道讀取到緩沖區(qū)中,或者從緩沖區(qū)寫入到通道中。Selector(選擇區(qū))用于多個通道的事件(比如:連接打開,數(shù)據(jù)到達(dá))。因此,單個線程可以多個數(shù)據(jù)通道。
NIO和傳統(tǒng)IO(一下簡稱IO)之間個的區(qū)別是,IO是面向流的,NIO是面向緩沖區(qū)的。 Java IO面向流意味著每次從流中讀一個或多個字節(jié),直至讀取所有字節(jié),它們沒有被緩存在任何地方。此外,它不能前后移動流中的數(shù)據(jù)。如果需要前后移動從流中讀取的數(shù)據(jù),需要先將它緩存到一個緩沖區(qū)。NIO的緩沖導(dǎo)向方法略有不同。數(shù)據(jù)讀取到一個它稍后處理的緩沖區(qū),需要時可在緩沖區(qū)中前后移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩沖區(qū)中包含所有您需要處理的數(shù)據(jù)。而且,需確保當(dāng)更多的數(shù)據(jù)讀入緩沖區(qū)時,不要覆蓋緩沖區(qū)里尚未處理的數(shù)據(jù)。
IO的各種流是阻塞的。這意味著,當(dāng)一個線程調(diào)用read() 或 write()時,該線程被阻塞,直到有一些數(shù)據(jù)被讀取,或數(shù)據(jù)完全寫入。該線程在此期間不能再干任何事情了。 NIO的非阻塞模式,使一個線程從某通道發(fā)送請求讀取數(shù)據(jù),但是它僅能得到目前可用的數(shù)據(jù),如果目前沒有數(shù)據(jù)可用時,就什么都不會獲取。而不是保持線程阻塞,所以直至數(shù)據(jù)變得可以讀取之前,該線程可以繼續(xù)做其他的事情。 非阻塞寫也是如此。一個線程請求寫入一些數(shù)據(jù)到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閑時間用于在其它通道上執(zhí)行IO操作,所以一個單獨(dú)的線程現(xiàn)在可以管理多個輸入和輸出通道(channel)。
Channel
首先說一下Channel,國內(nèi)大多翻譯成“通道”。Channel和IO中的Stream(流)是差不多一個等級的。只不過Stream是單向的,譬如:InputStream, OutputStream.而Channel是雙向的,既可以用來進(jìn)行讀操作,又可以用來進(jìn)行寫操作。
NIO中的Channel的主要實現(xiàn)有:·
FileChannel··
DatagramChannel··
SocketChannel·
ServerSocketChannel·
這里看名字就可以猜出個所以然來:分別可以對應(yīng)文件IO、UDP和TCP(Server和Client)。下面演示的案例基本上就是圍繞這4個類型的Channel進(jìn)行陳述的。
Buffer
NIO中的關(guān)鍵Buffer實現(xiàn)有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分別對應(yīng)基本數(shù)據(jù)類型: byte, char, double, float, int, long, short。當(dāng)然NIO中還有MappedByteBuffer, HeapByteBuffer, DirectByteBuffer等這里先不進(jìn)行陳述。
Selector
Selector運(yùn)行單線程處理多個Channel,如果你的應(yīng)用打開了多個通道,但每個連接的流量都很低,使用Selector就會很方便。例如在一個聊天服務(wù)器中。要使用Selector, 得向Selector注冊Channel,然后調(diào)用它的select()方法。這個方法會一直阻塞到某個注冊的通道有事件就緒。一旦這個方法返回,線程就可以處理這些事件,事件的例子有如新的連接進(jìn)來、數(shù)據(jù)接收等。