1、傳統(tǒng)IO,他是面向流的模式、阻塞式(read() 或write()時線程被阻塞,直到讀完)
2、NIO 面向緩沖區(qū)(Buffer)、非阻塞、selector
面向緩沖區(qū):可以對緩沖區(qū)中的數(shù)據(jù)進行靈活的操作,可以向前向后操作緩沖區(qū)里面的數(shù)據(jù)(而流只能按照讀取流的順序來操作)變得靈活,以空間換靈活。
非阻塞:其實這就是采用reactor 模式的好處。reactor pattern和observer pattern兩種模式類似, 區(qū)別在于前者與多個事件源關(guān)聯(lián), 后者與單個事件源關(guān)聯(lián). 這點區(qū)別, 又反過來印證了上述思想, reactor pattern和多個事件源關(guān)聯(lián), 每個事件的處理時間很短, 所以, 大家復(fù)用線程, 避免線程切換/同步/數(shù)據(jù)移動帶來的性能問題

NIO 一些基本知識:
- Channel
- Buffer
- Selector
所有的NIO 都是從Channel 開始,channel 和buffer之間可以互相讀寫,一般用戶不直接操作 往channel 里面些數(shù)據(jù),而是從buffer里面把數(shù)據(jù)寫入channel;或者 讀取數(shù)據(jù)也一般是從channel里面寫入buffer,然后在從buffer在讀取。
Selector :允許單線程處理多個channel,Selector 是一個中間管理者,負責(zé)channel的注冊,根據(jù)不同的方式(讀寫)選擇不同的server 或者 回傳。
Channel :channel 和流類似,但又不同,流是單向的,通道是雙向的。Channel的數(shù)據(jù)總先從buffer 中讀取,或者保存到buffer中。

主要包括 :
DatagramChannel ==》UDP 讀寫網(wǎng)絡(luò)數(shù)據(jù)
ServerSocketChannel ===》監(jiān)聽新連接,每一個請求都創(chuàng)建一個鏈接,像Http一樣
SocketChannel ===》TCP 請求
SourceChannel、SinkChannel ==》pip
Buffer :Buffer 用于和Channel 交互,數(shù)據(jù)是從channel 讀取入buffer,從buffer寫入channel。buffer本質(zhì)是一塊可以寫入數(shù)據(jù),并且讀取的內(nèi)存。
有3個數(shù)據(jù)很重要:
Capacity:
緩存區(qū)的最大容量,分配空間。你只能往里寫capacity個byte、long,char等類型
limit: 是 index
position: index
這兩個取決當(dāng)前是讀模式還是寫模式。
如果是寫模式: position 表示當(dāng)前寫的 位置,limit 最多能寫入多少數(shù)據(jù),和capacity值一樣。
如果是讀模式:切換到指定位置, position=0,從該區(qū)開始讀取,limit 表示已經(jīng)寫入的數(shù)據(jù)大小
flip()方法
flip方法將Buffer從寫模式切換到讀模式。調(diào)用flip()方法會將position設(shè)回0,并將limit設(shè)置成之前position的值。(把position設(shè)置為0)
Buffer 類型:
byteBuffer,charBuffer,shortBuffer,intBuffer,longBuffer,floatBuffer,longBuffer,MappedByteBuffer
先進行分配
往Buffer 寫數(shù)據(jù) 兩種方法:
1、int bytesize= fileChannel.read(buf);
2、通過put:
buf.put(112);
buffer 里面讀數(shù)據(jù) 2種方法
1、int bytewittern=fileChannel.write(buf);//把buffer的數(shù)據(jù)寫到channel中
2、buf.get();
rewind(): 重置讀取的位置,limit 不變。
clear()與compact()方法
Clear() ==>進行 緩沖區(qū)的標(biāo)志位重置,position =0,limit =capacity,mark=-1;
compat()==>定位到緩沖區(qū) 剩余數(shù)據(jù) 尾部,后面需要寫入數(shù)據(jù),接著位置寫進去。 Position 保持之前的 位置,limit=capacity,mark=-1;
mark()與reset()方法
標(biāo)識一個position,然后中途可以做一些事情, 需要回到標(biāo)示的地方,reset()
equals()與compareTo()方法
Equals :標(biāo)示緩沖區(qū)里面的剩余數(shù)據(jù)是否相等,跟緩沖區(qū)的capacity 無關(guān)。
CompareTo: 比較equals,如果equals:(結(jié)果< 比較者) 1、看第一個字母<第二個;2、比較buffer 比第二個先耗盡.
Channel 支持 Scatter/gather
Scatter channel 可以把數(shù)據(jù)寫入到不同的buffer中.
原理是,把數(shù)據(jù)依次寫到buffer中,當(dāng)前buffer寫滿了,往下一個buffer寫數(shù)據(jù)。

ByteBuffer headBuf=ByteBuffer.allocate(180);
ByteBuffer bodyBuf=ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);
Scattering Reads在移動下一個buffer前,必須填滿當(dāng)前的buffer,這也意味著它不適用于動態(tài)消息(譯者注:消息大小不固定)。換句話說,如果存在消息頭和消息體,消息頭必須完成填充(例如 128byte),Scattering Reads才能正常工作。
Grather 從多個buffer 寫到一個channel中。

ByteBuffer headBuf=ByteBuffer.allocate(180);
ByteBuffer bodyBuf=ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);
NIO selector
Selector 是一個用可以檢測到1到多個 channel 通道,并且知曉是 write 還是read 狀態(tài)的一個組件。由這個功能 可以用一個單線程管理多個channel,從而管理多個網(wǎng)絡(luò)鏈接。
使用selector 的好處是可以用更少的線程處理多個通道。
PIP
管道可以鏈接兩個線程之間的單向通信,source 是讀取流的一端,shink是將要寫入的端

NIO和IO的優(yōu)勢,使用場景
[NIO]
1.需要處理成千上完的請求,但是這些請求每次只是發(fā)送少量的數(shù)據(jù).例如聊天服務(wù)器.
2.單個線程管理多個鏈接
[IO]
少量的鏈接,一次性發(fā)送大量的數(shù)據(jù).