Selector簡介
Selector(選擇器)是javaNIO中能檢測一到多個(gè)NIO通道,并能夠知道通道是否為諸如讀寫事件做好準(zhǔn)備的組件。這樣的好處是,一個(gè)單獨(dú)的線程可以管理多個(gè)channel,從而可以管理多個(gè)網(wǎng)絡(luò)連接。
1.使用Selector的好處
對于操作系統(tǒng)而言,線程之間上下文切換的開銷很大,而且每個(gè)線程都要占用系統(tǒng)的一些資源。所以用單個(gè)線程來處理多個(gè)channels能提高性能。
但是現(xiàn)代操作系統(tǒng)和cpu在多任務(wù)方便表現(xiàn)的越來越好,所以多線程的開銷隨著時(shí)間的推移,變得越來越小了。所以可以使用多個(gè)Selector.
1.1Selector的創(chuàng)建
通過調(diào)用Selector.open()方法創(chuàng)建一個(gè)Selector
Selector selector = Selector.open();
1.2向Selector注冊通道
為了將Channel和Selector配合使用,必須將channel注冊到selector上,通過SelectableChannel.register()方法來實(shí)現(xiàn)。
channel.configureBlocking(false);
SelectionKey key = channel.register(selector,
Selectionkey.OP_READ);
register()方法的第二個(gè)參數(shù),這是一個(gè)“interest集合”,意思是在通過Selector監(jiān)聽Channel時(shí)對什么事情感興趣,有一下4中事件。
Connect
Accept
Read
Write
通道觸發(fā)了一個(gè)事件就是該事件已經(jīng)就緒。
SelectionKey.OP_CONNECT:某個(gè)channel成功連接到另一個(gè)服務(wù)器稱為“連接就緒”
SelectionKey.OP_ACCPET:一個(gè)server socket channel準(zhǔn)備好接收新進(jìn)入的連接稱為“接收就緒”
SelectionKey.OP_READ:一個(gè)有數(shù)據(jù)可讀的通道可以說是讀就緒。
SelectionKey.OP_WRITE.等待寫數(shù)據(jù)的通道可以說是寫就緒。
1.3SelectionKey
當(dāng)向Selector注冊Channel時(shí),register()方法會(huì)返回一個(gè)SelectionKey對象,這個(gè)對象包含了一些你感興趣的屬性。
interest集合:你所感興趣的事件集合
ready集合:通道已經(jīng)準(zhǔn)備就緒的集合
Channel:可以訪問channel Channel channel = selectionKey.channel();
Selector:可以訪問selector Selector selector = selectionKey.selector();
1.4Selector選擇通道
一旦向Selector注冊一個(gè)或者多個(gè)通道,可以調(diào)用幾個(gè)重載的select()方法,這些方法返回你所感興趣的事件(連接,接受,讀或?qū)懀┮呀?jīng)準(zhǔn)備就緒的哪些通道。
select():阻塞到至少有一個(gè)通道在你注冊上的事件就緒了。
select(long timeout):除了最長阻塞timeout毫秒
selectNow()不會(huì)阻塞:不管什么通道就緒都立刻返回。
1.5selectKeys()
一旦調(diào)用了select方法,并且返回值表明有一個(gè)或更多個(gè)通道就緒了,然后可以通過調(diào)用selector的selectedKeys()方法,訪問已選擇(selected key set)中的就緒通道。
Set selectedKeys = selector.selectedKeys();
可以遍歷這個(gè)已選擇的鍵集合來訪問就緒的通道。如下:
Set selectedKeys = selector.selectedKeys();
Iterator 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();
}
這個(gè)循環(huán)遍歷選擇鍵集中的每個(gè)鍵,并檢測各個(gè)鍵所對應(yīng)的通道的就緒事件。