Java NIO selector Selector

Selector

Selector is a component in Java NIO that can detect one or more NIO channels and know whether the channel is ready for events such as read and write. In this way, a single thread can manage multiple channels and thus multiple network connections. 

(1) Why use Selector? 
The advantage of using only a single thread to process multiple Channels is that fewer threads are required to process channels. In fact, all channels can be handled by only one thread. For the operating system, context switching between threads is expensive, and each thread occupies some resources of the system (such as memory). Therefore, the fewer threads used, the better. 
The following is an example diagram of a single thread using a Selector to process 3 channels: 


(2) 
Create a Selector Create a Selector by calling the Selector.open() method, as follows: 
Selector selector = Selector.open();  
(3) Registering the channel with the Selector 
In order to use the Channel with the Selector, the channel must be registered with the Selector. It is implemented by the SelectableChannel.register() method, as follows:
channel.configureBlocking(false);  
SelectionKey key = channel.register(selector,  Selectionkey.OP_READ);  
When used with Selector, Channel must be in non-blocking mode. This means that FileChannel cannot be used with Selector because FileChannel cannot be switched to non-blocking mode. And socket channels are fine. 
Note the second parameter of the register() method. This is an "interest collection", meaning what events are of interest when listening to the Channel through the Selector. Four different types of events can be listened for: 
  • Connect
  • Accept
  • Read
  • Write
Channel triggering an event means that the event is ready. Therefore, a channel successfully connecting to another server is called "connection ready". A server socket channel that is ready to receive incoming connections is called "ready to receive". A channel with data to read can be said to be "read-ready". A channel waiting to write data can be said to be "write ready". 
These four events are represented by the four constants of SelectionKey: 
  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE
If you are interested in more than one kind of event, you can use the "bitwise OR" operator to concatenate the constants, like this: 
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
(4) SelectionKey 
In the previous section, when registering Channel with Selector, the register() method will return a SelectionKey object. This object contains some properties of interest to you: 
  • interest collection
  • ready collection
  • Channel
  • Selector
  • additional object (optional)

interest collection 

As described in the Registering Channels with Selectors section, the interest collection is the collection of events of interest that you have selected. The interest collection can be read and written via the SelectionKey, like this: 

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;

As you can see, with the "bit AND" operation of the interest collection and a given SelectionKey constant, it is possible to determine whether a certain event is in the interest collection. 

ready set 
The ready set is the set of operations for which the channel is ready. After a selection, you will first access the ready set. Selection will be explained in the next subsection. You can access the ready set like this: 
int readySet = selectionKey.readyOps(); 
You can use the same method as the interest set to detect what events or operations are ready in the channel. However, the following four methods are also available, all of which return a boolean type:

selectionKey.isAcceptable ();  
selectionKey.isConnectable();  
selectionKey.isReadable();  
selectionKey.isWritable();
Channel + Selector 
Accessing Channel and Selector from SelectionKey is simple. as follows: 
Channel  channel  = selectionKey.channel();  
Selector selector = selectionKey.selector();  
Additional objects 
can attach an object or more information to the SelectionKey so that a given channel can be easily identified. For example, you can attach a Buffer used with a channel, or some object that contains aggregated data. The method of use is as follows:  
selectionKey.attach(theObject);  
Object attachedObj = selectionKey.attachment();  

You can also attach objects when registering the Channel with the Selector using the register() method. Such as: 

SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);  
(5) Channel selection via Selector 
Once one or more channels are registered with the Selector, several overloaded select() methods can be called. These methods return those channels that are ready for the event you are interested in (such as connect, accept, read, or write). In other words, if you are interested in "read-ready" channels, the select() method will return those channels that are ready for read events. 
Here is the select() method: 
  • int select()
  • int select(long timeout)
  • int selectNow()
select() blocks until at least one channel is ready for the event you registered for. 
select(long timeout) is the same as select(), except that it blocks for a maximum of timeout milliseconds (parameter). 
selectNow() does not block and returns immediately no matter what channel is ready.

The int value returned by the select() method indicates how many channels are ready. That is, how many channels have become ready since the last time the select() method was called. If the select() method is called, it returns 1 because one of the channels becomes ready, and if the select() method is called again, it will return 1 again if another channel is ready. If nothing was done on the first ready channel, there are now two ready channels, but between each select() method call, only one channel is ready. 

selectedKeys() 


Once the select() method is called, and the return value indicates that one or more channels are ready, the selectedKeys() method of the selector can then be accessed by calling the selectedKeys() method in the "selected key set". ready channel. As follows: 

Set selectedKeys = selector.selectedKeys();
When registering a Channel as a Selector, the Channel.register() method returns a SelectionKey object. This object represents the channel registered with this Selector. These objects can be accessed through the SelectKey's selectedKeySet() method. 


This selected set of keys can be traversed to access ready channels. as follows: 
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();
}  
    

This loop goes through each key in the selected key set and detects the ready event for the channel corresponding to each key. 
Note the keyIterator.remove() call at the end of each iteration. The Selector does not remove SelectionKey instances from the selected key set by itself. You must remove yourself when you are done processing the channel. The next time the channel becomes ready, the Selector will put it in the selected key set again. 

The channel returned by the SelectionKey.channel() method needs to be converted to the type you want to deal with, such as ServerSocketChannel or SocketChannel. 

(6) wakeUp() A 
thread is blocked after calling the select() method. Even if no channel is ready, there is a way to make it return from the select() method. Just let other threads call the Selector.wakeup() method on the object on which the first thread called the select() method. Threads blocked on the select() method will return immediately. 
If another thread calls the wakeup() method, but no thread is currently blocked on the select() method, the next thread that calls the select() method will "wake up" immediately. 

(7) close() 
calls its close() method after the Selector is used up to close the Selector and invalidate all SelectionKey instances registered on the Selector. The channel itself does not close. 

(8) Complete example 
Here is a complete example, open a Selector, register a channel to register on this Selector (the initialization process of the channel is omitted), and then continuously monitor the four events of this Selector (accept, connect, read, write) is ready. 

Selector selector = Selector.open();  
channel.configureBlocking(false);  
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);  
while(true) {  
  int readyChannels = selector.select();  
  if(readyChannels == 0) continue;  
  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();
}
}


 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325947773&siteId=291194637