Class SelectorSupport

java.lang.Object
org.dellroad.stuff.net.SelectorSupport
Direct Known Subclasses:
ChannelNetwork

public class SelectorSupport extends Object
Support for managing activity based on SelectableChannel asynchronous I/O notifications.

This class helps simplify the management of asynchronous I/O: all operations involving configuring and notifying I/O listeners are performed while this instance is locked, and all callbacks are performed in a separate service thread with this instance locked. As a result, all I/O operations are effectively atomic.

Instances must be start()ed before use. While running, an internal service thread continuously monitors for ready I/O operations, notifying the corresponding SelectorSupport.IOHandler when the I/O is ready (or channel closed). The service thread also performs periodic housekeeping.

Subclasses invoke createSelectionKey() to setup monitoring for a SelectableChannel, and then selectFor() as needed to configure the I/O conditions being monitored. All channels are automatically configured for non-blocking mode.

Housekeeping

Whether or not there is I/O activity, instances perform regular periodic housekeeping via serviceHousekeeping(). The maximum time between housekeeping checks is configurable via setHousekeepingInterval(); periodic checks can also be disabled by setting an interval of zero.

Whether or not periodic housekeeping checks are enabled, an immediate housekeeping check can be forced at any time by invoking wakeup().

Shutdown Cleanup

On shutdown, subclasses are given an opportunity to perform final cleanup via serviceCleanup().

Concurrency

This class guarantees that the current instance will be locked and the current thread will be the service thread when:

Because these callbacks are only ever invoked from the service thread, subclasses can be written without concern for re-entrancy issues, and subclass methods can use instance synchronization on other methods to avoid any race conditions from asynchronous I/O events.

  • Field Details

  • Constructor Details

  • Method Details

    • setHousekeepingInterval

      public void setHousekeepingInterval(int housekeepingInterval)
      Set the housekeeping interval.
      Parameters:
      housekeepingInterval - housekeeping interval in milliseconds, or zero for none
      Throws:
      IllegalArgumentException - if housekeepingInterval is negative
    • start

      public void start() throws IOException
      Start this instance.

      Does nothing if already started.

      Throws:
      IOException - if a Selector cannot be created
    • stop

      public void stop()
      Stop this instance.

      Does nothing if already stopped.

    • isRunning

      public boolean isRunning()
      Determine whether this instance has been start()'ed (and not yet stop()'d).
    • createSelectionKey

      public SelectionKey createSelectionKey(SelectableChannel channel, SelectorSupport.IOHandler handler) throws IOException
      Create a new SelectionKey by registering the given channel on this instance's Selector and associating the specified SelectorSupport.IOHandler to handle I/O ready conditions.

      This method is equivalent to: createSelectionKey(channel, handler, false).

      Parameters:
      channel - I/O channel
      handler - I/O handler
      Returns:
      new selection key
      Throws:
      IllegalArgumentException - if either parameter is null
      ClosedChannelException - if channel is closed
      IOException - if channel cannot be configured for non-blocking mode
      IllegalStateException - if this instance is not start()ed or is shutting down
    • createSelectionKey

      public SelectionKey createSelectionKey(SelectableChannel channel, SelectorSupport.IOHandler handler, boolean notifyOnClose) throws IOException
      Create a new SelectionKey by registering the given channel on this instance's Selector and associating the specified SelectorSupport.IOHandler to handle I/O ready conditions and/or channel closure.

      Note: the channel will be configured for non-blocking mode.

      Initially, no I/O operations will be selected. Use selectFor() to add/remove them.

      If notifyOnClose is true, the handler is also automatically invoked one last time after channel is closed (or the returned SelectionKey is cancel()'ed). However, this notification doesn't occur immediately; instead, it is only guaranteed to occur no later than the next housekeeping operation.

      There is no way to explicitly unregister handler from channel, although it can be selected for zero I/O operations. Handlers are implicitly unregistered either when channel is closed, the returned SelectionKey is cancel()'ed, or this instance is stop()'ed.

      Parameters:
      channel - I/O channel
      handler - I/O handler
      notifyOnClose - whether to also detect closure of channel and invoke handler one last time
      Returns:
      new selection key
      Throws:
      IllegalArgumentException - if either parameter is null
      ClosedChannelException - if channel is closed
      IOException - if channel cannot be configured for non-blocking mode
      IllegalStateException - if this instance is not start()ed or is shutting down
    • selectFor

      public void selectFor(SelectionKey selectionKey, int ops, boolean enabled)
      Enable or disable listening for the specified I/O operation(s).

      The given selectionKey must have been acquired from createSelectionKey().

      The change will take effect immediately.

      Parameters:
      selectionKey - selection key
      ops - I/O operations to enable or disable
      enabled - true to enable, false to disable
      Throws:
      IllegalArgumentException - if selectionKey was not created by createSelectionKey()
      IllegalArgumentException - if selectionKey is null
      IllegalArgumentException - if ops contains an invalid operation
    • wakeup

      public boolean wakeup()
      Wakeup the service thread.

      This results in an immediate invocation of serviceHousekeeping() (from the service thread).

      Does nothing if this instance is not start()ed.

      This method does not acquire the lock on this instance, so it can be invoked at any time from any context.

      Returns:
      true if service thread woken up, false if this instance is not started
    • serviceHousekeeping

      protected void serviceHousekeeping()
      Perform housekeeping.

      This method is invoked from the internal service thread; this instance will be locked at that time.

      This method is invoked after every I/O service (while still holding this instance's lock), and periodically at least every housekeeping interval, if enabled. If this method is invoked, it is guaranteed that this instance is not being stop()'ed.

      Any unchecked exceptions thrown by this method are logged but otherwise ignored. If a fatal error occurs, stop() may be invoked to initiate a graceful shutdown.

      Use wakeup() to trigger an immediate invocation of this method.

      The implementation in SelectorSupport does nothing.

    • serviceCleanup

      protected void serviceCleanup()
      Perform shutdown cleanups.

      This method is invoked at shutdown from the internal service thread; this instance will be locked at that time.

      Note: ay invocation from this method to createSelectionKey() will result in an IllegalStateException.

      The implementation in SelectorSupport does nothing.

    • dbg

      public static String dbg(Iterable<? extends SelectionKey> keys)
      Get a debug description of the given keys.
      Parameters:
      keys - selection keys
      Returns:
      debug description
    • dbg

      public static String dbg(SelectionKey key)
      Get a debug description of the given key.
      Parameters:
      key - selection key
      Returns:
      debug description
    • dbgOps

      public static String dbgOps(int ops)
      Get a debug description of the given I/O ops.
      Parameters:
      ops - I/O operation bits
      Returns:
      debug description
    • isServiceThread

      public boolean isServiceThread()
      Determine whether the current thread is this instance's service thread.
      Returns:
      true if the current thread is this instance's service thread