1. 程式人生 > >JAVA NIO Selector 知識三

JAVA NIO Selector 知識三

java nio


Selector(選擇器)


Selector工作流程:我們把想要的soketchannel告訴selector後,我們就去可以做別的事情,當有事件發生的時候,selector會通知我們,然後獲取selectionkey,獲得我們感興趣的事件。


selecotr是java nio多路復用的關鍵類,selector實現了一個線程管理多個channel,只需要更少的資源來處理更多的通道,節省線程之間的開銷,這麽說seletor是以前cpu很貴的時候,現在很多公司的機器都是多核,充分利用cpu才是最好的應用,後期會寫些JAVA NIO的最佳實踐netty。


下面寫幾個簡單的例子:

Seletor的創建方式:

Selector selector = Selector.open();


channel註冊到seletor上:

SelectionKey key = channel.register(selector,Selectionkey.OP_READ);


channel註冊到Selector後會返回一個SelectionKey對象,SelectionKey代表著這個channel和註冊的

selector的關系,SelectionKey維護著兩個重要的屬性interestOps和readyops。



Selector通常會監聽四種類型的事件:

  • connect

  • accept

  • read

  • write



這四種事件通常用Selectionkey對應的一些:

  • SelectionKey.OP_CONNECT

  • SelectionKey.OP_ACCEPT

  • SELECTIONKEY.OP_READ

  • SELECTIONKEY.OP_WRITE

//打開服務器端的套接字通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//服務器端設置為非阻塞
serverSocketChannel.configureBlocking(false);
//服務端進行綁定
serverSocketChannel.bind(new InetSocketAddress("localhost", 8000));

//註冊感興趣的事件
Selector selector = Selector.open();
SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
selectionKey.* 可以查看一些感興趣的事件



select()方法:

            int selectCount = selector.select();阻塞到至少有一個再註冊的通道上就緒了
            selector.select(timeout);這個有超時時間
            selector.selectNow();這個是到無論有沒有都立馬就返回了


selectedKeys()方法:

 Set<SelectionKey> keys = selector.selectedKeys();
            //獲取叠代器
 Iterator<SelectionKey> keyIterator = keys.iterator();


獲取我我們需要的監聽的事件;

while (keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();
    if (!key.isValid()) {
        continue;
    }
    if (key.isAcceptable()) {
        ServerSocketChannel  sscTemp = (ServerSocketChannel) key.channel();
        //得到一個連接好的SocketChannel,並把它註冊到Selector上,興趣操作為READ
        SocketChannel socketChannel = sscTemp.accept();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);
        System.out.println("REGISTER CHANNEL , CHANNEL NUMBER IS:" + selector.keys().size());
    } else if (key.isReadable()) {
        //讀取通道中的數據
        SocketChannel channel = (SocketChannel) key.channel();
        read(channel);
    }
    keyIterator.remove(); //該事件已經處理,可以丟棄
}

JAVA NIO Selector 知識三