【JAVA】【NIO】7、Java NIO Selector

來源:互聯網
上載者:User

標籤:java   nio   翻譯   selector   

selector是Java NIO的組件可以檢查一個或多個NIO的channel,並且決定哪個channel是為讀寫準備好了。這種方式,單個線程可以管理多個channel,也就是多個網路連接。

為什麼使用選取器

優點就是更少的線程去處理多個通道。實際上,你可以使用一個線程去處理所有的通道。作業系統中線程的切換是很費資源的,而且每個線程本身也佔用了一些資源(記憶體)。所以使用的線程越少越好!

現在的作業系統和CPU在多任務上變得越來越好,所以多線程的開銷也變得更小了。事實上,如果一個CPU有多個核心,不用多線程可能是一種浪費。不管怎麼說,設計討論應該是在另一篇文章說。在這裡,知道用selector,單線程去處理多通道就足夠了。

建立選取器

通過調用Selector.open()方法建立。

註冊通道

channel.configureBlocking(false);配置通道為非阻塞模式
channel.register(selector,SelectionKey.OP_ACCEPT);通過該方法註冊

使用selector,channel必須是非阻塞模式。意味著FileChannel不用使用selector,因為FileChannel不能轉為非阻塞模式。SocketChannel可以正常使用。

注意register方法的第二個參數。這是一個興趣集合,意思是通過selector監聽這個channel時,對什麼樣的事件感興趣。有如下幾種:
1、Connect
2、Accept
3、Read
4、Write

一個通道觸發了一個事件意思就是對該事件準備就緒了。所以,一個channel和伺服器串連成功了就是串連就緒。ServerSocketChannel接受了串連就是接受就緒。一個通道有資料準備好被讀了就是讀就緒。一個通道準備寫入資料就是寫就緒。
這四中事件通過SelectionKey的四個常量來定義:
1、SelectionKey.OP_CONNECT
2、SelectionKey.OP_ACCEPT
3、SelectionKey.OP_READ
4、SelectionKey.OP_WRITE
如果你對多個事件有興趣,可以如下來寫:

int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

在文章靠後將會回到興趣集來講解。

SelectionKey’s

正如前面所述,當你通過selector給通道註冊,register方法將返回一個SelectionKey對象,這個對象包含了一些你感興趣的屬性:
·The interest set
·The ready set
·The Channel
·The Selector
·An attached object (optional)

Interest Set

interest集合是你感興趣的事件集合。你可以通過SelectionKey讀寫興趣集合,如下:

int interestSet = selectionKey.interestOps();

boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT;
boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;
boolean isInterestedInRead = interestSet & SelectionKey.OP_READ;
boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;

你可以通過&操作找出某個事件是否是興趣集合的。

Ready Set

ready集合是channel為哪些操作已經就緒了。在一次選擇後,你會首先訪問ready集合,如下:

int readySet = selectionKey.readyOps();

同樣你可以像上面提到的方法一樣通過&來測試哪些操作已經就緒了。但是同樣你可以通過如下方法來得到:

selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable();

Channel + Selector

通過SelectionKey訪問channel+selector很簡單,如下:

Channel channel = selectionKey.channel();

Selector selector = selectionKey.selector();

Attaching Objects

可以將一個對象或者更多資訊附加到SelectionKey上以便識別一個具體的通道。例如,你可以附加和通道一起使用的Buffer或者一個包含很多聚集資料的對象,如下:

selectionKey.attach(theObject);

Object attachedObj = selectionKey.attachment();

你也可以再register的時候就附加對象

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

Selecting Channels via a Selector

一旦你通過selector註冊了多個通道,你可以調用selecto方法。這些方法返回為興趣集合(串連,接收,讀,寫)事件就緒的通道。換言之,如果你對對讀就緒的通道感興趣, 你就會通過select方法返回讀就緒的通道。
以下是select方法:
·int select()
·int select(long timeout)
·int selectNow()
select()方法會阻塞直到至少一個通道是為你註冊的事件就緒的。
select(long timeout)和select()一樣,除了它阻塞會有一個逾時時間。
selectNow()沒有阻塞,無論什麼通道,就緒就立刻返回。
select()方法返回的int表示有多少通道就緒了,即自從最後一次調用select()方法以來,有多少通道就緒了。如果你調用select方法返回1,說明有一個通道就緒了,你再次調用返回1,說明另一個通道就緒了。如果你對第一個就緒的通道什麼都不做,你現在就有兩個就緒通道,但是僅僅只有一個通道就緒在每次select方法調用過程中。

selectedKeys()

一旦你調用了一個select()方法並且傳回值,表明一個或多個通道就緒了,你可以通過selected key集合訪問就緒通道,通過調用selectedKeys方法實現,如下:

Set selectedKeys = selector.selectedKeys();

當你註冊了一個通道事件時會返回一個SelectionKey對象。這個對象表示註冊到該Selector上的通道。你可以通過selectedKeySet訪問這些keys。如下:

Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while(keyIterator.hasNext()) {    SelectionKey key = keyIterator.next();    if(key.isAcceptable()) {        // a connection was accepted by a ServerSocketChannel.    } else if (key.isConnectable()) {        // a connection was established with a remote server.    } else if (key.isReadable()) {        // a channel is ready for reading    } else if (key.isWritable()) {        // a channel is ready for writing    }    keyIterator.remove();}

這個迴圈遍曆selected key集合。並檢測各個鍵對應的通道就緒事件。
注意每次迭代末尾的keyIterator.remove()調用。Selector不會自己從已選擇鍵集中移除SelectionKey執行個體。必須在處理完通道時自己移除。下次該通道變成就緒時,Selector會再次將其放入已選擇鍵集中。

SelectionKey.channel()方法返回的channel需要轉型成你需要的,例如ServerSocketChannel,SocketChannel等。

wakeUp()

一個線程調用select方法阻塞了,即使沒有就緒通道,也可以讓select方法返回。讓其它線程通過剛剛調用select方法的Selector對象調用wakeup方法即可。阻塞在select方法上的線程會立即返回。
如果其它線程調用了wakeup,但是當前沒有線程阻塞在select,那麼下一個調用select方法的線程會立即喚醒。

close()

用完Selector要調用close方法。關閉Selector並且將所有註冊在selector上的鍵集作廢。通道自己不會關閉。

完整執行個體
package nio;import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.util.Iterator;import java.util.Set;public class SelectorDemo {    public static void main(String[] args) throws IOException {        //開啟伺服器通訊端通道        ServerSocketChannel ssc = ServerSocketChannel.open();        //非阻塞模式        ssc.configureBlocking(false);        //擷取與此通道關聯的伺服器通訊端        ServerSocket ss = ssc.socket();        //服務綁定        ss.bind(new InetSocketAddress(8990));        //開啟一個選取器        Selector selector = Selector.open();        //在該選取器上註冊通道事件        SelectionKey registerKey = ssc.register(selector, SelectionKey.OP_ACCEPT);        while(true) {            int readyChannels = selector.select();            if(readyChannels==0) {                System.out.println("No Channel Is Ready !");                continue;            }            Set<SelectionKey> selectedKeys = selector.selectedKeys();            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();            while(keyIterator.hasNext()) {                SelectionKey key = keyIterator.next();                if(key.isAcceptable()) {                    System.out.println("接收操作!");                }else if(key.isConnectable()) {                    System.out.println("串連操作!");                }else if(key.isReadable()) {                    System.out.println("讀操作!");                }else if(key.isWritable()) {                    System.out.println("寫操作!");                }                keyIterator.remove();            }        }    }}

以上代碼注意,在註冊事件時只能是ACCEPT,其它事件在外面註冊都會導致程式運行失敗,因為其它所有事件都是在ACCEPT後才能夠註冊的,所以要注意這一點。

下一節:等待

【JAVA】【NIO】7、Java NIO Selector

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.