NIO 常用的編程模型是 Reactor,在 Doug Lea 的 Scalable IO in Java 的 PPT 中對其進行了介紹,文末有福利 :) ,Reactor 的特點是 I/O 多路複用和事件驅動,基本處理過程爲:
- 處理程序聲明感興趣的 I/O 事件,這些事件表示在特定套接字上準備讀取的情況
- 事件通知器等待事件
- 一個事件發生並喚醒通知器,通知器調用適當的處理程序
- 事件處理程序執行實際的讀取操作,並進行處理,然後重新聲明關注的 I/O 事件,並將控制權返回給調度程序
其中通知器,就是 Selector。Reactor模型主要有以下幾種版本:
- 單線程Reactor,單線程處理器
- 單線程Reactor,多線程處理器
- 多線程主從Reactor,單線程處理器
- 多線程主從Reactor,多線程處理器
單線程版本
核心代碼:
public void run() {
try {
if (state == READING) read();
else if (state == SENDING) send();
} catch (IOException ex) { /* ... */ }
}
void read() throws IOException {
socket.read(input);
if (inputIsComplete()) {
process();
state = SENDING;
// Normally also do first write now
sk.interestOps(SelectionKey.OP_WRITE);
}
}
void send() throws IOException {
socket.write(output);
if (outputIsComplete()) sk.cancel();
}
單線程的特點是:只有一個 Reactor 線程,即只有一個 Selector 事件通知器,也就是說,字節的讀取 I/O 和後續的業務處理(process() 方法),均由 Reactor 線程來做,很顯然業務的處理影響後續事件的分發,所以引出多線程版本進行優化。
多線程版本
核心代碼:
static PooledExecutor pool = new PooledExecutor(...);
static final int PROCESSING = 3;
// ...
synchronized void read() { // ...
socket.read(input);
if (inputIsComplete()) {
state = PROCESSING;
pool.execute(new Processer());
}
}
synchronized void processAndHandOff() {
process();
state = SENDING; // or rebind attachment
sk.interest(SelectionKey.OP_WRITE);
}
class Processer implements Runnable {
public void run() { processAndHandOff(); }
}
多線程版本的特點是:一個 Reactor 線程和多個處理線程,將業務處理(process 交給線程池)進行了分離,Reactor 線程,只關注事件分發和字節的發送和讀取(I/O)。注意,實際的發送和讀取還是由 Reactor 處理,那麼在高併發下,有可能連接來不及接收,繼續優化,採用主從 Reactor。
主從 Reactor
核心代碼:
Selector[] selectors; // also create threads
int next = 0;
class Acceptor { // ...
public synchronized void run() { ...
Socket connection = serverSocket.accept();
if (connection != null)
new Handler(selectors[next], connection);
if (++next == selectors.length) next = 0;
}
}
主從 Reactor 特點是:使用一個 Selector 池,通常有一個 主Reactor 用於處理接收連接事件,多個 從Reactor 處理實際的 I/O,整體來看,分工合作,分而治之,非常高效。
在真正實現時,有些細節需要注意,完整代碼下載:https://github.com/rmwheel/reactor
代碼有詳細註釋,看完絕對能理解 Reactor,其中包含對 Doug Lea 的 Scalable IO in Java 的 翻譯,歡迎 star :)