天天看點

Java NIO SelectorJava NIO Selector

Java Nio 

1

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/index.html">Java NIO Tutorial</a>

2

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/overview.html">Java NIO Overview</a>

3

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/channels.html">Java NIO Channel</a>

4

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/buffers.html">Java NIO Buffer</a>

5

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/scatter-gather.html">Java NIO Scatter / Gather</a>

6

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/channel-to-channel-transfers.html">Java NIO Channel to Channel Transfers</a>

7

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html">Java NIO Selector</a>

8

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/file-channel.html">Java NIO FileChannel</a>

9

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/socketchannel.html">Java NIO SocketChannel</a>

10

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/server-socket-channel.html">Java NIO ServerSocketChannel</a>

11

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/datagram-channel.html">Java NIO DatagramChannel</a>

12

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/pipe.html">Java NIO Pipe</a>

13

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/nio-vs-io.html">Java NIO vs. IO</a>

Java NIO SelectorJava NIO Selector

Rate article:

Share article:

<a target="_blank" href="https://twitter.com/share">Tweet</a>

Table of Contents

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#why-use-a-selector">Why Use a Selector?</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#creating-a-selector">Creating a Selector</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#registering-channels-with-the-selector">Registering Channels with the Selector</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#selectionkey">SelectionKey's</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#selector-interest-sets">Interest Set</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#selector-ready-set">Ready Set</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#channel-selector">Channel + Selector</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#attaching-objects">Attaching Objects</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#wakeup">wakeUp()</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#close">close()</a>

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/selectors.html#full-selector-example">Full Selector Example</a>

A <code>Selector</code> 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.

<a target="_blank"></a>

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 by not 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 a <code>Selector</code>.

Here is an illustration of a thread using a <code>Selector</code> to handle 3 <code>Channel</code>'s:

Java NIO SelectorJava NIO Selector

Java NIO: A Thread uses a Selector to handle 3 Channel's

You create a <code>Selector</code> by calling the <code>Selector.open()</code> method, like this:

In order to use a <code>Channel</code> with a <code>Selector</code> you must register the <code>Channel</code> with the <code>Selector</code>. This is done using the <code>SelectableChannel.register()</code> method, like this:

The <code>Channel</code> must be in non-blocking mode to be used with a <code>Selector</code>. This means that you cannot use<code>FileChannel</code>'s with a <code>Selector</code> since <code>FileChannel</code>'s cannot be switched into non-blocking mode. Socket channels will work fine though.

Notice the second parameter of the <code>register()</code> method. This is an "interest set", meaning what events you are interested in listening for in the <code>Channel</code>, via the <code>Selector</code>. 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 <code>SelectionKey</code> 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:

I'll return to the interest set a bit further down in this text.

As you saw in the previous section, when you register a <code>Channel</code> with a <code>Selector</code> the <code>register()</code> method returns a <code>SelectionKey</code> objects. This <code>SelectionKey</code> 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.

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 the <code>SelectionKey</code> like this:

As you can see, you can AND the interest set with the given <code>SelectionKey</code> constant to find out if a certain event is in the interest 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:

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:

Accessing the channel + selector from the <code>SelectionKey</code> is trivial. Here is how it's done:

You can attach an object to a <code>SelectionKey</code> this is a handy way of recognizing a given channel, or attaching further information to the channel. For instance, you may attach the <code>Buffer</code> you are using with the channel, or an object containing more aggregate data. Here is how you attach objects:

You can also attach an object already while registering the <code>Channel</code> with the <code>Selector</code>, in the <code>register()</code> method. Here is how that looks:

Once you have register one or more channels with a <code>Selector</code> you can call one of the <code>select()</code> 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 <code>select()</code> methods.

Here are the <code>select()</code> methods:

int select()

int select(long timeout)

int selectNow()

<code>select()</code> blocks until at least one channel is ready for the events you registered for.

<code>select(long timeout)</code> does the same as <code>select()</code> except it blocks for a maximum of <code>timeout</code> milliseconds (the parameter).

<code>selectNow()</code> doesn't block at all. It returns immediately with whatever channels are ready.

The <code>int</code> returned by the <code>select()</code> methods tells how many channels are ready. That is, how many channels that became ready since last time you called <code>select()</code>. If you call <code>select()</code> and it returns 1 because one channel has become ready, and you call <code>select()</code> 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 each <code>select()</code> call.

Once you have called one of the <code>select()</code> 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 selectors <code>selectedKeys()</code>method. Here is how that looks:

When you register a channel with a <code>Selector</code> the <code>Channel.register()</code> method returns a <code>SelectionKey</code> object. This key represents that channels registration with that selector. It is these keys you can access via the<code>selectedKeySet()</code> method. From the <code>SelectionKey</code>.

You can iterate this selected key set to access the ready channels. Here is how that looks:

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 <code>keyIterator.remove()</code> call at the end of each iteration. The <code>Selector</code> does not remove the<code>SelectionKey</code> 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" the <code>Selector</code> will add it to the selected key set again.

The channel returned by the <code>SelectionKey.channel()</code> method should be cast to the channel you need to work with, e.g a ServerSocketChannel or SocketChannel etc.

A thread that has called the <code>select()</code> method which is blocked, can be made to leave the <code>select()</code> method, even if no channels are yet ready. This is done by having a different thread call the <code>Selector.wakeup()</code> method on the<code>Selector</code> which the first thread has called <code>select()</code> on. The thread waiting inside <code>select()</code> will then return immediately.

If a different thread calls <code>wakeup()</code> and no thread is currently blocked inside <code>select()</code>, the next thread that calls<code>select()</code> will "wake up" immediately.

When you are finished with the <code>Selector</code> you call its <code>close()</code> method. This closes the <code>Selector</code> and invalidates all<code>SelectionKey</code> instances registered with this <code>Selector</code>. The channels themselves are not closed.

Here is a full example which opens a <code>Selector</code>, registers a channel with it (the channel instantiation is left out), and keeps monitoring the <code>Selector</code> for "readiness" of the four events (accept, connect, read, write).

<a target="_blank" href="http://tutorials.jenkov.com/java-nio/file-channel.html">Next:   Java NIO FileChannel</a>