Java NIO Selector
来源:互联网 发布:腾讯大数据 手游 编辑:程序博客网 时间:2024/05/02 01:28
A Selector
is a Java NIO component which can examine one or more NIO Channel's, and determine which channels are ready for e.g. reading or writing. This way a single thread can manage multiple channels, and thus multiple network connections.
Here is a list of the topics covered in this text:
- Why Use a Selector?
- Creating a Selector
- Registering Channels with a Selector
- SelectionKey's
- Selecting Channels via a Selector
- wakeUp()
- close()
- Full Example
Why Use a Selector?
The advantage of using just a single thread to handle multiple channels is that you need less threads to handle the channels. Actually, you can use just one thread to handle all of your channels. Switching between threads is expensive for an operating system, and each thread takes up some resources (memory) in the operating system too. Therefore, the less threads you use, the better.
Keep in mind though, that modern operating systems and CPU's become better and better at multitasking, so the overheads of multithreading becomes smaller over time. In fact, if a CPU has multiple cores, you might be wasting CPU power bynot multitasking. Anyways, that design discussion belongs in a different text. It suffices to say here, that you can handle multiple channels with a single thread, using aSelector
.
Here is an illustration of a thread using a Selector
to handle 3 Channel
's:
Creating a Selector
You create a Selector
by calling the Selector.open()
method, like this:
Selector selector = Selector.open();
Registering Channels with the Selector
In order to use a Channel
with a Selector
you must register theChannel
with the Selector
. This is done using the SelectableChannel.register()
method, like this:
channel.configureBlocking(false);SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
The Channel
must be in non-blocking mode to be used with a Selector
. This means that you cannot use FileChannel
's with aSelector
since FileChannel
's cannot be switched into non-blocking mode. Socket channels will work fine though.
Notice the second parameter of the register()
method. This is an "interest set", meaning what events you are interested in listening for in theChannel
, via the Selector
. There are four different events you can listen for:
- Connect
- Accept
- Read
- Write
A channel that "fires an event" is also said to be "ready" for that event. So, a channel that has connected successfully to another server is "connect ready". A server socket channel which accepts an incoming connection is "accept" ready. A channel that has data ready to be read is "read" ready. A channel that is ready for you to write data to it, is "write" ready.
These four events are represented by the four SelectionKey
constants:
- SelectionKey.OP_CONNECT
- SelectionKey.OP_ACCEPT
- SelectionKey.OP_READ
- SelectionKey.OP_WRITE
If you are interested in more than one event, OR the constants together, like this:
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
I'll return to the interest set a bit further down in this text.
SelectionKey's
As you saw in the previous section, when you register a Channel
with aSelector
the register()
method returns a SelectionKey
objects. ThisSelectionKey
object contains a few interesting properties:
- The interest set
- The ready set
- The Channel
- The Selector
- An attached object (optional)
I'll describe these properties below.
Interest Set
The interest set is the set of events you are interested in "selecting", as described in the section "Registering Channels with the Selector". You can read and write that interest set via theSelectionKey
like this:
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;
As you can see, you can AND the interest set with the given SelectionKey
constant to find out if a certain event is in the interest set.
Ready Set
The ready set is the set of operations the channel is ready for. You will primarily be accessing the ready set after a selection. Selection is explained in a later section. You access the ready set like this:
int readySet = selectionKey.readyOps();
You can test in the same way as with the interest set, what events / operations the channel is ready for. But, you can also use these four methods instead, which all reaturn a boolean:
selectionKey.isAcceptable();selectionKey.isConnectable();selectionKey.isReadable();selectionKey.isWritable();
Channel + Selector
Accessing the channel + selector from the SelectionKey
is trivial. Here is how it's done:
Channel channel = selectionKey.channel();Selector selector = selectionKey.selector();
Attaching Objects
You can attach an object to a SelectionKey
this is a handy way of recognizing a given channel, or attaching further information to the channel. For instance, you may attach theBuffer
you are using with the channel, or an object containing more aggregate data. Here is how you attach objects:
selectionKey.attach(theObject);Object attachedObj = selectionKey.attachment();
You can also attach an object already while registering the Channel
with theSelector
, in the register()
method. Here is how that looks:
SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);
Selecting Channels via a Selector
Once you have register one or more channels with a Selector
you can call one of theselect()
methods. These methods return the channels that are "ready" for the events you are interested in (connect, accept, read or write). In other words, if you are interested in channels that are ready for reading, you will receive the channels that are ready for reading from the select()
methods.
Here are the select()
methods:
- int select()
- int select(long timeout)
- int selectNow()
select()
blocks until at least one channel is ready for the events you registered for.
select(long timeout)
does the same as select()
except it blocks for a maximum oftimeout
milliseconds (the parameter).
selectNow()
doesn't block at all. It returns immediately with whatever channels are ready.
The int
returned by the select()
methods tells how many channels are ready. That is, how many channels that became ready since last time you calledselect()
. If you call select()
and it returns 1 because one channel has become ready, and you callselect()
one more time, and one more channel has become ready, it will return 1 again. If you have done nothing with the first channel that was ready, you now have 2 ready channels, but only one channel had become ready between eachselect()
call.
selectedKeys()
Once you have called one of the select()
methods and its return value has indicated that one or more channels are ready, you can access the ready channels via the "selected key set", by calling the selectorsselectedKeys()
method. Here is how that looks:
Set<SelectionKey> selectedKeys = selector.selectedKeys();
When you register a channel with a Selector
the Channel.register()
method returns aSelectionKey
object. This key represents that channels registration with that selector. It is these keys you can access via theselectedKeySet()
method. From the SelectionKey
.
You can iterate this selected key set to access the ready channels. Here is how that looks:
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();}
This loop iterates the keys in the selected key set. For each key it tests the key to determine what the channel referenced by the key is ready for.
Notice the keyIterator.remove()
call at the end of each iteration. TheSelector
does not remove the SelectionKey
instances from the selected key set itself. You have to do this, when you are done processing the channel. The next time the channel becomes "ready" theSelector
will add it to the selected key set again.
The channel returned by the SelectionKey.channel()
method should be cast to the channel you need to work with, e.g a ServerSocketChannel or SocketChannel etc.
wakeUp()
A thread that has called the select()
method which is blocked, can be made to leave theselect()
method, even if no channels are yet ready. This is done by having a different thread call theSelector.wakeup()
method on the Selector
which the first thread has calledselect()
on. The thread waiting inside select()
will then return immediately.
If a different thread calls wakeup()
and no thread is currently blocked insideselect()
, the next thread that calls select()
will "wake up" immediately.
close()
When you are finished with the Selector
you call its close()
method. This closes theSelector
and invalidates all SelectionKey
instances registered with thisSelector
. The channels themselves are not closed.
Full Example
Here is a full example which opens a Selector
, registers a channel with it (the channel instantiation is left out), and keeps monitoring theSelector
for "readiness" of the four events (accept, connect, read, write).
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<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(); }}
- Java NIO Selector
- JAVA NIO之selector
- Java NIO(7-Selector)
- Java NIO Selector
- Java NIO Selector
- java NIO- Selector
- Java nio selector
- Java NIO Selector
- Java NIO--Selector
- Java NIO (六) Selector
- Java NIO Selector
- Java NIO(3)----Selector
- Java NIO之Selector
- Java NIO Selector
- Java NIO Selector
- Java NIO之Selector
- Java NIO 之selector
- java NIO Selector详解
- 开源日志系统log4cplus(四)
- Java util之常用数据类型特性盘点
- 神乎其技,惟C程序,功到自成,写好C程序的10条秘籍
- 开源日志系统log4cplus(五)
- 设计模式(3)观察者模式(Observer)
- Java NIO Selector
- java web开发,bean数据放在request、response还是servletcontext中?
- 开源日志系统log4cplus(六)
- Android学习第6课—常见控件(一)
- 开源日志系统log4cplus(七)
- 数据库设计中的一些问题
- Android各版本市场份额:冰激凌仅2% 姜饼66.5%
- c# webbrowser与winform交互访问,javascript参数调用控制程序
- 安全字符串处理函数