Selectors
The java.nio.channels.Selector class is the crucial component of nonblocking I/O. It is the class that enables your program to determine which channels are ready to be accessed when. The only constructor is protected, and subclassing this class yourself would be unusual. Instead, you create a Selector by opening it with the static Selector.open( ) method:
public static Selector open( ) throws IOException
Each Selector may be registered with several SelectableChannels, as discussed in the last section. Registration is threadsafe and ongoing. You can register the Selector with various channels at any time.
When your program has a little time to do some work, you ask the Selector which of its channels are ready, that is, which channels can be read or written without blocking. You do this by invoking one of these three methods:
public abstract int selectNow( ) throws IOException public abstract int select( ) throws IOException public abstract int select(long timeout) throws IOException
All three methods return the number of keys whose readiness states were changed by this selection. Important: this is not necessarily the number of keys that are ready to be operated on! Extra keys may well have been ready before the selection and may still be ready. You rarely need to know how many keys' readiness states were changed by the selection, so the return values of these methods are generally ignored.
The selectNow( ) method is nonblocking, whereas the other two methods block. selectNow( ) returns immediately even if it can't select anything. The other two methods return only after they select some channel, the thread is interrupted, or the timeout expires. Even in nonblocking I/O, you tend to use blocking selects if there's nothing for the program to do except I/O. Example 16-2 is a case in point. However, if your program can do something useful even when no channel is ready, you might use selectNow( ) instead of select( ).
After you've called one of these methods, the selectedKeys( ) method returns a java.util.Set containing keys for all the ready channels registered with this Selector:
public abstract Set selectedKeys( )
The returned set contains zero or more SelectionKey objects. Like a lot of similar methods, Java 5 retrofits this method's signature with generics to make it a little more typesafe:
public abstract Set selectedKeys( )
In both Java 1.4 and 5, you normally iterate though this Set using an Iterator and process each key in turn, as shown in Example 16-2. However, there are other patterns. For instance, you could reselect after processing one key:
while (true) { selector.select( ); Set readyKeys = selector.selectedKeys( ); Iterator iterator = readyKeys.iterator( ); if (iterator.hasNext( )) { SelectionKey key = (SelectionKey) iterator.next( ); iterator.remove( ); // process key... } }
Selectors may use native system resources. Once you're done with one, you should close it by invoking its close( ) method:
public abstract void close( ) throws IOException
Otherwise, your program may leak memory and other resources, though details vary by platform. Closing a Selector deregisters all its associated keys and wakes up any threads waiting on the select( ) methods. Any further attempts to use a closed Selector or one of its keys throws an exception. If you don't know whether a Selector is closed, you can check with the isOpen( ) method:
public abstract boolean isOpen( )
|
In a high-volume system, even the blocking select methods are likely to return very quickly. In a less stressful environment, though, select( ) can block a thread for some time. Another thread can wake up a thread blocked by a select( ) method by invoking the Selector's wakeup( ) method:
public abstract Selector wakeup( )
You can actually wake up a Selector before it selects. In this case, the next call to select( ) returns immediately.