Java NIO 入門

關于多路復用

很多人用過InputStreamOutputStream接口,用來操作文件、Socket等等 IO 操作。
如果是簡單的,速度較快的 IO 操作,我們用Stream類的接口,依然可以風生水起。
如果你要使用非阻塞的 IO 的話,他們可能就滿足不了你了。

熟悉操作系統(tǒng)的人會知道,操作非阻塞 IO 無非幾種多路復用:

  1. select
  2. poll
  3. epoll
  4. kqueue
  5. IOCP

這里的復用模型有幾個是操作系統(tǒng)相關的——也就是說,并不是所有的操作系統(tǒng)都可以用,典型的就是IOCPWindows的"專利",kqueueBSD的"專利"(比如macOS)。

那么 java 作為一門跨平臺的語言解決方案,是如何在虛擬機上使用 non-blocking IO 的呢?
具體的實現(xiàn)我們可以不管,它使用了Selector的 API,調(diào)用方式非常類似select。

Channel & ByteBuffer vs Stream

nio中,不再使用Stream APISocket進行交互,而是使用ChannelByteBuffer進行交互,
Channel負責管道的工作,ByteBuffer負責緩存的工作。

原先InputStreamOutputStream的工作就由Channel做掉了,如果這個Channel支持Select模型的話,它就是SelectableChannel的子類。
那么,在消息循環(huán)的模型中,首先要建立循環(huán),像我們的Looper.loop()一樣,我們先用Selector.open()新建一個Selector

Selector eventSelector = Selector.open();

// 設置這個 channel 是非阻塞的
socketChannel.configureBlocking(false);

// 注冊到 selector 里,并設置好關心的事件
socketSelectionKey = socketChannel.register(eventSelector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

Selector

接下來調(diào)用 eventSelector.select() 阻塞,就能在你關心的事件到來的時候,阻塞就會被喚醒,處理事件。

sample:

while (connected) {
    eventSelector.select();
    Set<SelectionKey> keys = eventSelector.selectedKeys();
    Iterator<SelectionKey> iterator = keys.iterator();
    while (iterator.hasNext()) {
        SelectionKey key = iterator.next();
        if (key.isReadable()) {
            // 當 socket 可讀
            internalOnRead((ReadableByteChannel) key.channel());
        }

        if (key.isWritable()) {
            // 當 socket 可寫
            internalOnWrite((WritableByteChannel) key.channel());
        }
        iterator.remove();
    }
}

總結

nio 對于客戶端的優(yōu)勢幾乎沒有,但是可以讓代碼更好管理; 如果這時候你使用的是ServerSocket,好處就立馬體現(xiàn)了,因為你的業(yè)務需求很可能是這樣:

  1. master 線程,開啟 accept.
  2. 如果有客戶接入,開啟一個 worker,用來服務 client。
  3. 服務完后,保持或者關閉這個連接。

(這個業(yè)務模型類似Apache httpd)這樣的業(yè)務模型可能導致過多的線程開銷,使得并發(fā)量并不高。

那么,老生常談的event-driven的模型在java中,就差不多是這樣的邏輯:

  1. master 線程,開啟 selector, 并為 ServerSocket 注冊 accept, read, write 等事件。
  2. 客戶接入,為 client socket 注冊 read, write 事件,依舊在該線程里面進行循環(huán)。
  3. 當 event trigger 的時候,處理相關業(yè)務邏輯。

第二個模型只啟動了一個線程,所有的IO操作都在 OS 里面完成了,用戶空間內(nèi)的資源消耗大大降低,這也是我們把 Server 端的 IO 改成 nio 的優(yōu)勢。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容