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