Selector
一、什么是selector
selector?一般稱為選擇器?,當(dāng)然你也可以翻譯為?多路復(fù)用器?。它是Java NIO核心組件中的一個(gè),用于檢查一個(gè)或多個(gè)NIO Channel(通道)的狀態(tài)是否處于可讀、可寫。如此可以實(shí)現(xiàn)單線程管理多個(gè)channels,也就是可以管理多個(gè)網(wǎng)絡(luò)鏈接。
? ? ? ? ? ? ? ??
?
二、使用selector
1. Selector的創(chuàng)建
通過調(diào)用Selector.open()方法創(chuàng)建一個(gè)Selector對(duì)象,如下:
Selector selector = Selector.open();2. 注冊(cè)Channel到Selector,Channel必須是非阻塞的。?
ssc.configureBlocking(false); //設(shè)置為非阻塞 SelectionKey key = channel.register(selector, Selectionkey.OP_READ)(1)要先創(chuàng)建channel :
ServerSocketChannel ssc = ServerSocketChannel.open();ssc.socket().bing(new InetSocketAddress("localhost",9999))
//ssc.socket() : 檢索與此通道關(guān)聯(lián)的服務(wù)器套接字,返回一個(gè)ServerSocket
注意:abstract SelectableChannel configureBlocking(boolean block)? 可以設(shè)置是否有阻塞
SelectableChannel抽象類的configureBlocking()?方法是由?AbstractSelectableChannel抽象類實(shí)現(xiàn)的,SocketChannel、ServerSocketChannel、 DatagramChannel都是直接繼承了?AbstractSelectableChannel抽象類?。?
(2)channel.register( )第二個(gè)參數(shù):
register()?方法的第二個(gè)參數(shù)。這是一個(gè)“?interest集合?”,意思是在通過Selector監(jiān)聽Channel時(shí)對(duì)什么事件感興趣。可以監(jiān)聽四種不同類型的事件:
- Connect? :connect==1<<3==8==0000 1000
- Accept :accept==1<<4==16==0001 0000
- Read? :?read ==1<<0? ==1?==0000 0001
- Write? :write==1<<2==4==0000 0100
通道觸發(fā)了一個(gè)事件意思是該事件已經(jīng)就緒。
1)比如某個(gè)Channel成功連接到另一個(gè)服務(wù)器稱為“?連接就緒?”。
2)一個(gè)Server Socket Channel準(zhǔn)備好接收新進(jìn)入的連接稱為“?接收就緒?”。
3)一個(gè)有數(shù)據(jù)可讀的通道可以說是“?讀就緒?”。
4)等待寫數(shù)據(jù)的通道可以說是“?寫就緒?”。
這四種事件用SelectionKey的四個(gè)常量來表示:
SelectionKey.OP_CONNECT //連接就緒? SelectionKey.OP_ACCEPT //接收就緒 SelectionKey.OP_READ //讀就緒 SelectionKey.OP_WRITE //寫就緒(3) 一個(gè)SelectionKey鍵表示了一個(gè)特定的通道對(duì)象和一個(gè)特定的選擇器對(duì)象之間的注冊(cè)關(guān)系。
key.attachment(); //返回SelectionKey的attachment,attachment可以在注冊(cè)channel的時(shí)候指定。 key.channel(); // 返回該SelectionKey對(duì)應(yīng)的channel。 key.selector(); // 返回該SelectionKey對(duì)應(yīng)的Selector。 key.interestOps(); //返回代表需要Selector監(jiān)控的IO操作的bit mask key.readyOps(); // 返回一個(gè)bit mask,代表在相應(yīng)channel上可以進(jìn)行的IO操作。1)key.interestOps();?可以通過以下方法來判斷Selector是否對(duì)Channel的某種事件感興趣
int interestSet = selectionKey.interestOps(); boolean isInterestedInAccept = (interestSet & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT; boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;首先“~”符號(hào)代表按位取反,“&”代表按位與
selectionKey.interestOps()得到當(dāng)前的,我們不管他是多少,假設(shè)是write 也就是0000 0100 ,而read按位取反后就是1111 1110 ,與上面的進(jìn)行“&”操作
read的取反一共八位,七位為1 一位為0,為1的與先前的write進(jìn)行“&”操作則保持不變,原來是多少就是多少,0與前面的“&”操作就是置0
2)key.readyOps()
/創(chuàng)建ready集合的方法 int readySet = selectionKey.readyOps(); //檢查這些操作是否就緒的方法 key.isAcceptable();//是否可讀,是返回 true boolean isWritable()://是否可寫,是返回 true boolean isConnectable()://是否可連接,是返回 true boolean isAcceptable()://是否可接收,是返回 true
3、Selector維護(hù)的三種類型SelectionKey集合:
-
已注冊(cè)的鍵的集合(Registered key set)
所有與選擇器關(guān)聯(lián)的通道所生成的鍵的集合稱為已經(jīng)注冊(cè)的鍵的集合。并不是所有注冊(cè)過的鍵都仍然有效。這個(gè)集合通過?keys()?方法返回,并且可能是空的。這個(gè)已注冊(cè)的鍵的集合不是可以直接修改的;試圖這么做的話將引發(fā)java.lang.UnsupportedOperationException。
-
已選擇的鍵的集合(Selected key set)
所有與選擇器關(guān)聯(lián)的通道所生成的鍵的集合稱為已經(jīng)注冊(cè)的鍵的集合。并不是所有注冊(cè)過的鍵都仍然有效。這個(gè)集合通過?keys()?方法返回,并且可能是空的。這個(gè)已注冊(cè)的鍵的集合不是可以直接修改的;試圖這么做的話將引發(fā)java.lang.UnsupportedOperationException。
-
已取消的鍵的集合(Cancelled key set)
已注冊(cè)的鍵的集合的子集,這個(gè)集合包含了?cancel()?方法被調(diào)用過的鍵(這個(gè)鍵已經(jīng)被無效化),但它們還沒有被注銷。這個(gè)集合是選擇器對(duì)象的私有成員,因而無法直接訪問。
4、通過Selector的select()方法可以選擇已經(jīng)準(zhǔn)備就緒的通道
int select():阻塞到至少有一個(gè)通道在你注冊(cè)的事件上就緒了。 int select(long timeout):和select()一樣,但最長(zhǎng)阻塞時(shí)間為timeout毫秒。 int selectNow():非阻塞,只要有通道就緒就立刻返回。select()方法返回的int值表示有多少通道已經(jīng)就緒,是自上次調(diào)用select()方法后有多少通道變成就緒狀態(tài)。
一旦調(diào)用select()方法,并且返回值不為0時(shí),則 可以通過調(diào)用Selector的selectedKeys()方法來訪問已選擇鍵集合?。
如下:?
Set selectedKeys=selector.selectedKeys();?
進(jìn)而可以放到和某SelectionKey關(guān)聯(lián)的Selector和Channel。如下所示:
5. 停止選擇的方法
選擇器執(zhí)行選擇的過程,系統(tǒng)底層會(huì)依次詢問每個(gè)通道是否已經(jīng)就緒,這個(gè)過程可能會(huì)造成調(diào)用線程進(jìn)入阻塞狀態(tài),那么我們有以下三種方式可以喚醒在select()方法中阻塞的線程。
(1)wakeup()方法?:通過調(diào)用Selector對(duì)象的wakeup()方法讓處在阻塞狀態(tài)的select()方法立刻返回該方法使得選擇器上的第一個(gè)還沒有返回的選擇操作立即返回。如果當(dāng)前沒有進(jìn)行中的選擇操作,那么下一次對(duì)select()方法的一次調(diào)用將立即返回
(2)close()方法?:通過close()方法關(guān)閉Selector,?該方法使得任何一個(gè)在選擇操作中阻塞的線程都被喚醒(類似wakeup()),同時(shí)使得注冊(cè)到該Selector的所有Channel被注銷,所有的鍵將被取消,但是Channel本身并不會(huì)關(guān)閉。
原文鏈接:https://www.cnblogs.com/snailclimb/p/9086334.html
?
轉(zhuǎn)載于:https://www.cnblogs.com/dongtian-blogs/p/10736704.html
總結(jié)
- 上一篇: 在vue2.x项目中怎么引入Elemen
- 下一篇: RabbitMQ 相关概念和方法详解