示例代碼位置:https://git.oschina.net/silentwu/nio-tutorial.git
一.基本概念解析
1) 阻塞和非阻塞 :
阻塞和非阻塞是進(jìn)程在訪問(wèn)數(shù)據(jù)的時(shí)候,數(shù)據(jù)內(nèi)是否準(zhǔn)備就緒的一種處理方式 , 當(dāng)數(shù)據(jù)沒(méi)有準(zhǔn)備的時(shí)候 阻塞:往往需要等待緩沖區(qū)中的數(shù)據(jù)準(zhǔn)備好過(guò)后才處理其他的事情届垫,否則一直等待在那里
非阻塞 : 當(dāng)我們的進(jìn)程訪問(wèn)我們的數(shù)據(jù)緩沖區(qū)的時(shí)候 數(shù)據(jù)沒(méi)有準(zhǔn)備好的時(shí)候 直接返回 不需要等待 . 數(shù)據(jù)有的時(shí)候 也直接返回 .
2) 同步和異步的方式:
同步和異步都是基于應(yīng)用程序和操作系統(tǒng)處理 IO 時(shí)間鎖采用的方式 . 比如同步應(yīng)用程序要直接參與 IO 讀寫的操作 , 異步:所有的 IO 讀寫交給操作系統(tǒng)去處理 . 同步的方式在處理 IO 事件的時(shí)候 必須阻塞在某個(gè)方法上面等待我們的 IO 時(shí)間完成 ( 阻塞 IO 事件或則通過(guò)輪詢 IO 事件的方式 ), 對(duì)于異步來(lái)說(shuō)钧排,所有的 IO 讀寫都交給了操作系統(tǒng) 這個(gè)時(shí)候 我們可以去做其他的事情 并不需要去完成真正的 IO 操作,當(dāng)操作完成 IO 后 給我們的應(yīng)用程序一個(gè)通知就可以的符衔,
同步 :1) 阻塞到 IO 事件 阻塞到 read 或則 write. 這個(gè)時(shí)候我們就完全不能做自己的事情 . 讓讀寫方法加入到線程里面 然后阻塞線程來(lái)實(shí)現(xiàn) . 對(duì)線程的性能開(kāi)銷比較大 .
3)IO 事件的輪詢 – 多路復(fù)用技術(shù) (select 模式 )
讀寫事件交給一個(gè)單獨(dú)的線程來(lái)處理,這個(gè)完成 IO 事件的注冊(cè)供判族,還有就是不斷的去輪詢我們的讀寫緩沖區(qū) 看是否有數(shù)據(jù)準(zhǔn)備好。 通知我們通知相應(yīng)讀寫線程 . 這樣的話 以前的讀寫線程就可以做其他的事情 這個(gè)時(shí)候阻塞的不是所有的 IO 線程 阻塞的 select 這個(gè)線程 .
Client Select 管家 BOSS
當(dāng)客人來(lái)的時(shí)候 , 就給管家說(shuō) 我來(lái)了槽惫,管家得到這個(gè)注冊(cè)信息后辩撑, 給 BOSS 說(shuō) 我這里有一個(gè)或則多個(gè)客人 , BOSS 你去給某人 A
這件東西各薇,給另外人 B 這樣?xùn)|西君躺。這個(gè)時(shí)候 客人是可以去做自己的事情的,比如看看花園等等棕叫, 當(dāng)管家知道 boss 給他任務(wù)后 他就是去找對(duì)應(yīng)的某人 告訴他 boss 給他某樣?xùn)|西。(根據(jù)我們的注冊(cè)信息)
二.Java IO 模型
BIO:JDK1.4 以前我們使用都是 BIO 阻塞 IO
阻塞到我們的讀寫方法 , 阻塞到線程來(lái)提供性能 . 對(duì)于線程的開(kāi)銷本來(lái)就是性能的浪費(fèi) .
NIO:jdk1.4 linux 多路復(fù)用技術(shù) (select 模式 ) 實(shí)現(xiàn) IO 事件的輪詢方式 : 同步非阻塞的模式 . 這個(gè)種方式目前是主流的網(wǎng)絡(luò)通信模式 .
Mina 疗认, netty mina2.0 netty5.0— 網(wǎng)絡(luò)通信框架 . 比我直接寫 NIO 要容易些 并且代碼可讀性更好
AIO:jdk1.7 (NIO2) 才是實(shí)現(xiàn)真正的異步 aio 伏钠,學(xué)習(xí) linux epoll 模式
AIO 使用的比較少 , 大家可以認(rèn)真的學(xué)習(xí)一些思想
小結(jié) :
1)BIO 阻塞的 IO
2)NIO select+ 非阻塞 同步非阻塞
3)異步非阻塞 IO
三.NIO AIO 原理的解讀
對(duì)于網(wǎng)絡(luò)通信而言 NIO 贝润, AIO 并沒(méi)有改變網(wǎng)通通信的基本步驟,只是在其原來(lái)的基礎(chǔ)上 (serverscoket,socket) 做了一個(gè)改進(jìn) .
Socket <—- 建立連接需要三次握手 —–> serversocket
對(duì)于三次握手的方式建立穩(wěn)定的連接性能開(kāi)銷比較大 . 解決方案從思想上來(lái)說(shuō)比較容易 就是減少連接的次數(shù) . 對(duì)我們的讀寫通信管道進(jìn)行一個(gè)抽象 .
原理四.NIO 原理
通過(guò) selctor (選擇器)就相當(dāng)管家 华畏,管理所有的 IO 事件
Connction accept 客服端和服務(wù)端的讀寫 .—–IO 事件
selctor (選擇器)如何進(jìn)行管理 IO 事件
當(dāng) IO 事件注冊(cè)給我們的選擇器的時(shí)候 選擇器會(huì)給他們分配一個(gè) key (可以簡(jiǎn)單的理解成一個(gè)時(shí)間的標(biāo)簽) 當(dāng) IO 事件完成過(guò)通過(guò) key 值來(lái)找到相應(yīng)的管道 然后通過(guò)管道發(fā)送數(shù)據(jù)和接收數(shù)據(jù)等操作 .
數(shù)據(jù)緩沖區(qū):
通過(guò) bytebuffer 亡笑,提供很多讀寫的方法 put () get ()
服務(wù)端: ServerSocketChannel
客服端 : SocketChannel
選擇器 : Selector selector=Select.open(); 這樣就打開(kāi)了我們的選擇器 .
五. Selectionkey:
可以通過(guò)它來(lái)判斷 IO 事件是否已經(jīng)就緒 .
key.isAccptable: 是否可以接受客戶端的連接
Key.isconnctionable: 是否可以連接服務(wù)端
Key.isreadable(): 緩沖區(qū)是否可讀
Key.iswriteable(): 緩沖區(qū)是否可寫
六. 如何獲得事件的 keys
Selectionkey keys= Selector.selectedkeys();
七. 如何注冊(cè)
channel.regist(Selector,Selectionkey.OP_Write);
channel.regist(Selector,Selectionkey.OP_Read);
channel.regist(Selector,Selectionkey.OP_Connct);
channel.regist(Selector,Selectionkey.OP_Accept);
八. AIO:
服務(wù)端 :AsynchronousServerSocketChannel
客服端 :AsynchronousSocketChannel
用戶處理器 :CompletionHandler 接口 , 這個(gè)接口實(shí)現(xiàn)應(yīng)用程序向操作系統(tǒng)發(fā)起 IO 請(qǐng)求 , 當(dāng)完成后處理具體邏輯横朋,否則做自己該做的事情 .