1. 程式人生 > >Selector(非同步IO)

Selector(非同步IO)

非同步IO是一種沒有阻塞的讀寫資料的方法,通常,在程式碼進行 read() 呼叫時,程式碼會阻塞直至有可供讀取的資料。同樣,write() 呼叫將會阻塞直至資料能夠寫入。

非同步 I/O 的一個優勢在於,它允許您同時根據大量的輸入和輸出執行 I/O。同步程式常常要求助於輪詢,或者建立許許多多的執行緒以處理大量的連線。使用非同步 I/O,您可以監聽任何數量的通道上的事件,不用輪詢,也不用額外的執行緒。

非同步 I/O 中的核心物件名為 Selector。Selector 就是您註冊對各種 I/O 事件的地方,而且當那些事件發生時,就是這個物件告訴您所發生的事件。

第一步:建立一個Selector

       Selector selector = Selector.open();

第二步:開啟一個遠端連線

       InetSocketAddress socketAddress =

new InetSocketAddress("www.baidu.com", 80);

       SocketChannel sc = SocketChannel.open(socketAddress);

       sc.configureBlocking(false);

第三步:選擇鍵,註冊

       SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);

註冊時第一個引數總是當前的這個selector。

註冊讀事件:SelectionKey key = sc.register(selector, SelectionKey.OP_READ);

註冊寫事件:SelectionKey key = sc.register(selector, SelectionKey.OP_WRITE);

第四步:內部迴圈處理

int num = selector.select();

Set selectedKeys = selector.selectedKeys();

Iterator it = selectedKeys.iterator();

while (it.hasNext()) {

SelectionKey key = (SelectionKey)it.next();

// ... deal with I/O event ...

}

首先,我們呼叫 Selector 的 select() 方法。這個方法會阻塞,直到至少有一個已註冊的事件發生。當一個或者更多的事件發生時, select() 方法將返回所發生的事件的數量。該方法必須首先執行。

接下來,我們呼叫 Selector 的 selectedKeys() 方法,它返回發生了事件的 SelectionKey 物件的一個 集合 。

我們通過迭代 SelectionKeys 並依次處理每個 SelectionKey 來處理事件。對於每一個 SelectionKey,您必須確定發生的是什麼 I/O 事件,以及這個事件影響哪些 I/O 物件。

第五步:監聽事件並做出處理

SelectionKey中共定義了四種事件,OP_ACCEPT(socket accept)、OP_CONNECT(socket connect)、OP_READ(read)、OP_WRITE(write)。

第六步:刪除處理過的SelectionKey

在處理 SelectionKey 之後,我們幾乎可以返回主迴圈了。但是我們必須首先將處理過的 SelectionKey 從選定的鍵集合中刪除。

如果我們沒有刪除處理過的鍵,那麼它仍然會在主集合中以一個啟用的鍵出現,這會導致我們嘗試再次處理它。

我們呼叫迭代器的 remove() 方法來刪除處理過的 SelectionKey:it.remove();