IO指Blocking IO
NIO指new/non-blocking IO
Blocking IO中降允,對于每一個連接,創(chuàng)建一個線程處理這個連接的IO事件激涤,連接和處理線程之間有1:1的關(guān)系拟糕。連接數(shù)受到JVM線程數(shù)的限制。JVM最大線程數(shù)限制參考http://jzhihui.iteye.com/blog/1271122倦踢,最大線程數(shù)由操作系統(tǒng)支持線程數(shù)送滞,java初始堆大小,最大堆大小以及每個線程棧大小決定辱挥。
NIO使用單個selector可處理多個連接犁嗅。
IO核心代碼
final Socket clientSocket = socket.accept();
new Thread(new Runnable() {
@Override
public void run() {
...
}
}).start();
服務(wù)端socket.accept()阻塞直至接受新的connection。
接受新的connection之后晤碘,建立新的線程褂微,處理這個連接,每一個連接都有一個線程處理园爷,連接數(shù)和線程數(shù)是1:1的關(guān)系宠蚂。客戶端并發(fā)的線程數(shù)由同時存活線程數(shù)決定童社。
NIO的基礎(chǔ)概念
NIO使用selector-based方法來處理網(wǎng)絡(luò)數(shù)據(jù)和事件(The NIO API uses a selector-based approach to handle network events and data)
ByteBuffer:數(shù)據(jù)容器(不影響原理的理解求厕,之后再講)。
NIO Selectors:Selector is a NIO component that determines if one or more channels are ready for reading and/or扰楼。
選擇器:選擇器是一個組件呀癣,這個組件可以決定此時是否有一個或多個的channels準備好進行讀寫。由于Selector可以處理多個連接弦赖,減輕了IO中的線程負擔项栏。
Channel: A channel represents a connection to an entity capable of performing IO operations such as a file or socket.
通道:通道是指連向可進行IO操作實體的連接。通道本質(zhì)上是特殊的連接蹬竖,特殊在其連接的對象都可進行IO操作沼沈。NIO的通道似乎都是雙向的。
Selector的使用币厕,需要5步
創(chuàng)建一個Selector庆冕,使得其它的Channel可以注冊到Selector
在注冊Channel時,要說明Selector對此Channel感興趣的時間
OP_ACCEPT:socket-accept operations的操作位
OP_CONNECT:socket-connect
OP_READ:read operation
OP_WRITE:write operation
調(diào)用Selector.select()阻塞劈榨,指導(dǎo)上述事件發(fā)生
事件發(fā)生之后访递,可以獲取到SelectionKey實例,每個實例都包括Channel的引用和實際發(fā)生的事件同辣。
此版本NIO核心代碼
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
try {
selector.select();
} catch (IOException ex) {
ex.printStackTrace();
// handle in a proper way
break;
}
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel)
key.channel();
SocketChannel client = server.accept();
System.out.println("Accepted connection from " +
client);
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_WRITE |
SelectionKey.OP_READ, ByteBuffer.allocate(100));
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
client.read(output);
}
if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
output.flip();
client.write(output);
output.compact();
}
} catch (IOException ex) {
key.cancel();
try {
key.channel().close();
} catch (IOException cex) {
}
}
}
從代碼中可以看出此版本NIO需要開發(fā)者檢查網(wǎng)絡(luò)事件發(fā)生拷姿,同時觸發(fā)相應(yīng)的處理邏輯惭载。
NIO2
NIO允許分發(fā)IO操作,當IO操作完成時使用completion handler處理IO事件响巢。completion handler的執(zhí)行完全由底層系統(tǒng)決定描滔,對開發(fā)者隱藏。同時保證了每個channel同時
只有一個completion handler在執(zhí)行踪古。
NIO2核心代碼
channel.read(buffer, buffer,new EchoCompletionHandler(channel));
當讀取的IO完成之后含长,自動執(zhí)行Echo CompletionHandler的操作。
private final class EchoCompletionHandler implements
CompletionHandler {}
上述內(nèi)容講了
1. IO和NIO的本質(zhì)區(qū)別:IO的thread-per-connection的本質(zhì)以及NIO selector-based approch to handle network data and event.
2. IO實現(xiàn)伏穆,NIO1實現(xiàn)以及NIO2實現(xiàn)方式的區(qū)別拘泞,IO使用accept()阻塞等待連接發(fā)生之后,創(chuàng)建新的線程處理此連接枕扫;NIO1使用selector對channel進行監(jiān)聽陪腌,使用selector.select()阻塞直到某個channel準備好讀或?qū)懀枰_發(fā)者檢測事件的發(fā)生并提供相應(yīng)的處理邏輯烟瞧。NIO1是異步的诗鸭,selector可監(jiān)聽多個channel,這本質(zhì)上不同于IO参滴;NIO2同樣是基于selector但是NIO2的好處在于允許分發(fā)IO强岸,并且提供了complete handler用于在IO完成時,自動執(zhí)行砾赔,這種方法不需要檢測事件是否發(fā)生请唱,然后使用相應(yīng)的處理邏輯,這一切由底層實現(xiàn)过蹂。
參考:《netty in action》