SelectableChannel接口定义

Channel接口定义: http://donald-draper.iteye.com/blog/2369111
AbstractInterruptibleChannel接口定义: http://donald-draper.iteye.com/blog/2369238
上一篇文章我们讲到可以异步中断和关闭通道接口的定义。先来回顾一下:
   AbstractInterruptibleChannel是一个可以异步关闭和中断IO阻塞线程的通道,所有具体的通道实现,如果想要可以异步关闭和中断,必须实现此类。AbstractInterruptibleChannel内部有一个Open布尔值用于表示通道是否打开。在通道关闭时调用implCloseChannel方法完成
实际的关闭通道工作。有个中断处理器用于记录中断阻塞IO操作线程的线程,完成实际的关闭通道工作。有一组协调方法为begin和end方法,一般在一个可能阻塞的IO操作的开始调用begin,之后调用end方法,这些操作一般用一个try语句块,组合使用。begin方法主要初始化中断处理器,end方法根据IO操作是否完成和Open状态,及中断线程处理器,中断线程判断是抛出AsynchronousCloseException异常还是ClosedByInterruptException。
ServerSocketChannel父类结构树:
//ServerSocketChannel
public abstract class ServerSocketChannel
    extends AbstractSelectableChannel
    implements NetworkChannel

//AbstractSelectableChannel
public abstract class AbstractSelectableChannel
    extends SelectableChannel

//SelectableChannel
public abstract class SelectableChannel
    extends AbstractInterruptibleChannel
    implements Channel

今天我们来看一下可选择通道SelectableChannel的定义:
package java.nio.channels;

import java.io.IOException;
import java.nio.channels.spi.AbstractInterruptibleChannel;
import java.nio.channels.spi.SelectorProvider;


/**
 * A channel that can be multiplexed via a {@link Selector}.
 *
 SelectableChannel是可以通过选择器多路复用的通道。
 *  In order to be used with a selector, an instance of this class must
 * first be <i>registered</i> via the {@link #register(Selector,int,Object)
 * register} method.  This method returns a new {@link SelectionKey} object
 * that represents the channel's registration with the selector.
 *
 如果想要被选择器selector使用,通道的实体类必须先通道register(Selector,int,Object)
 方法,将通道关注的事件SelectionKey和Attaching的Object注册到选择器中。注册方法返回一个
SelectionKey对象,表示通道注册到选择器中的注册器。
 *  Once registered with a selector, a channel remains registered until it
 * is <i>deregistered</i>.  This involves deallocating whatever resources were
 * allocated to the channel by the selector.
 *
 只要通道注册到选择器中,直到调用deregistered方法,才能将通道从选择器移除。
 无论选择器分配什么资源给通道,deregistered方法被调用时,相关资源将会被收回。
 * <p> A channel cannot be deregistered directly; instead, the key representing
 * its registration must be <i>cancelled</i>.  Cancelling a key requests that
 * the channel be deregistered during the selector's next selection operation.
 * A key may be cancelled explicitly by invoking its {@link
 * SelectionKey#cancel() cancel} method.  All of a channel's keys are cancelled
 * implicitly when the channel is closed, whether by invoking its {@link
 * Channel#close close} method or by interrupting a thread blocked in an I/O
 * operation upon the channel.
 *
 通道不能直接从选择器反注册;取而代之的是,通过注册时返回的SelectionKey,SelectionKey
 是必须可以被cancelled的。SelectionKey取消后,在选择器下一次选择操作中,通道将会被反注册。
 可以通道SelectionKey#cancel的方法显示地取消SelectionKey。在通道关闭时,无论是否调用
Channel#close,阻塞IO操作线程是否被中断,所有跟通道相关联的SelectionKey将会被取消。
 * <p> If the selector itself is closed then the channel will be deregistered,
 * and the key representing its registration will be invalidated, without
 * further delay.
 *
 如果选择器自己关闭,所有注册到选择器的通道将会被反注册,同时与通道相关的SelectionKey,
 将会立即无效。
 * <p> A channel may be registered at most once with any particular selector.
 *
 一个通道可以被多次注册到一个特殊的选择器中。
 * <p> Whether or not a channel is registered with one or more selectors may be
 * determined by invoking the {@link #isRegistered isRegistered} method.
 *
 判断一个线程是否一次或多次注册到选择器,我们可以通过isRegistered方法来确定。
 * <p> Selectable channels are safe for use by multiple concurrent
 * threads. 

 *
 可选择的通道在多线程并发访问的情况下,必须是线程安全的。
 *
 * <a name="bm">
 * <h4>Blocking mode</h4>
 *
 阻塞模式
 * A selectable channel is either in <i>blocking</i> mode or in
 * <i>non-blocking</i> mode.  In blocking mode, every I/O operation invoked
 * upon the channel will block until it completes.  In non-blocking mode an I/O
 * operation will never block and may transfer fewer bytes than were requested
 * or possibly no bytes at all.  The blocking mode of a selectable channel may
 * be determined by invoking its {@link #isBlocking isBlocking} method.
 *
 一个可选择的通道要么是可阻塞的,要么是不可阻塞的。在阻塞模式下,通道的IO操作将会阻塞,直到
 器完成。在非阻塞模式下,IO操作绝对不会被阻塞,IO操作可能接受少于请求的数据或者就没有。
 通道的阻塞模式,我们可以通过#isBlocking方法来判断。
 *  Newly-created selectable channels are always in blocking mode.
 * Non-blocking mode is most useful in conjunction with selector-based
 * multiplexing.  A channel must be placed into non-blocking mode before being
 * registered with a selector, and may not be returned to blocking mode until
 * it has been deregistered.
 *
 一个新创建的可选择通道总是阻塞模式。非阻塞模式在基于多路复用的选择器中非常有用,
 一个通道在注册到选择器前,必须是非阻塞模式,直到反注册之前,都处于非阻塞模式中。
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 *
 * @see SelectionKey
 * @see Selector
 */

public abstract class SelectableChannel
    extends AbstractInterruptibleChannel
    implements Channel
{

    /**
     * Initializes a new instance of this class.
     */
    protected SelectableChannel() { }

    /**
     * Returns the provider that created this channel.
     *
     返回创建通道的提供者,这个在以后我们遇到时,才具体地将
     * @return  The provider that created this channel
     */
    public abstract SelectorProvider provider();

    /**
     * Returns an [url=SelectionKey.html#opsets]operation set[/url]
     * identifying this channel's supported operations.  The bits that are set
     * in this integer value denote exactly the operations that are valid for
     * this channel.  This method always returns the same value for a given
     * concrete channel class. 

     *
     返回通道支持的SelectionKey操作opsets。integer值中的bit位表示相关的操作,对于
     本通道有效。本方法总是返回相同的值,在具体的通道中。
     * @return  The valid-operation set
     */
    public abstract int validOps();

    // Internal state:
    //   keySet, may be empty but is never null, typ. a tiny array
    //   boolean isRegistered, protected by key set
    //   regLock, lock object to prevent duplicate registrations
    //   boolean isBlocking, protected by regLock

    /**
     * Tells whether or not this channel is currently registered with any
     * selectors.  A newly-created channel is not registered.
     *
     潘丹当前通道是否注册到选择器。新创建的通道是非注册的。
     *  Due to the inherent delay between key cancellation and channel
     * deregistration, a channel may remain registered for some time after all
     * of its keys have been cancelled.  A channel may also remain registered
     * for some time after it is closed.  

     *
     由于在SelectKey取消操作和通道反注册之间,存在内部的时延,在所有通道的SelectKey取消时,
     有时一个通道可能仍处于注册状态。在通道关闭后,有时可能仍处于注册状态。
     * @return <tt>true</tt> if, and only if, this channel is registered
     */
    public abstract boolean isRegistered();
    //
    // sync(keySet) { return isRegistered; }

    /**
     * Retrieves the key representing the channel's registration with the given
     * selector.  
     *
     获取通道上次注册到选择器的SelectionKey,没有注册,则返回null
     * @return  The key returned when this channel was last registered with the
     *          given selector, or <tt>null</tt> if this channel is not
     *          currently registered with that selector
     */
    public abstract SelectionKey keyFor(Selector sel);
    //同步keySet,返回刚注册到选择器的SelectionKey
    // sync(keySet) { return findKey(sel); }

    /**
     * Registers this channel with the given selector, returning a selection
     * key.
     *
     注册通道到指定的选择器,并返回一个SelectionKey。
     *  If this channel is currently registered with the given selector then
     * the selection key representing that registration is returned.  The key's
     * interest set will have been changed to <tt>ops</tt>, as if by invoking
     * the {@link SelectionKey#interestOps(int) interestOps(int)} method.  If
     * the <tt>att</tt> argument is not <tt>null</tt> then the key's attachment
     * will have been set to that value.  A {@link CancelledKeyException} will
     * be thrown if the key has already been cancelled.
     *
     如果通道当前已经注册到指定的选择器,表示注册器的SelectionKey将会被返回。
     只要SelectionKey#interestOps(int) 方法被调用,那么 SelectionKey关注事件将会被更新到ops中。
     如果att参数不为null,则SelectionKey的attachment将会被赋值为att。如果SelectionKey已经被取消,
     将抛出CancelledKeyException。
     *  Otherwise this channel has not yet been registered with the given
     * selector, so it is registered and the resulting new key is returned.
     * The key's initial interest set will be <tt>ops</tt> and its attachment
     * will be <tt>att</tt>.
     *
     如果通道还没有注册到通道,在注册完成后,将会返回一个新创建的SelectionKey,
     SelectionKey的初始关注集将会被设值为ops,attachment设值为att。
     * <p> This method may be invoked at any time.  If this method is invoked
     * while another invocation of this method or of the {@link
     * #configureBlocking(boolean) configureBlocking} method is in progress
     * then it will first block until the other operation is complete.  This
     * method will then synchronize on the selector's key set and therefore may
     * block if invoked concurrently with another registration or selection
     * operation involving the same selector. 

     *
     此方可以被任何时候调用。当其他方法调用或者configureBlocking(boolean)正在进行,
     调用此方法将会阻塞,直到其他操作完成。此方法将会同步选择器的SelectionKey集合,
     因此如果其他通道注册或选择操作涉及到同一个选择器等操作并发,此操作也许会阻塞。
     *  If this channel is closed while this operation is in progress then
     * the key returned by this method will have been cancelled and will
     * therefore be invalid. 

     *
     当操作正在进行,但通道被关闭,那么注册返回的注册器SelectionKey将会被取消,
     并无效。
     * @param  sel,选择器
     *         The selector with which this channel is to be registered
     *
     * @param  ops,关注的操作事件
     *         The interest set for the resulting key
     *
     * @param  att 附加对象
     *         The attachment for the resulting key; may be <tt>null</tt>
     *
     * @throws  ClosedChannelException,如果通道关闭抛出ClosedChannelException
     *          If this channel is closed
     *
     * @throws  ClosedSelectorException,如果选择器关闭抛出ClosedSelectorException
     *          If the selector is closed
     *
     * @throws  IllegalBlockingModeException,如果通道为阻塞模式,则抛出IllegalBlockingModeException
     *          If this channel is in blocking mode
     *
     * @throws  IllegalSelectorException,如果通道不是通过与选择器相同的provider创建,
     则抛出IllegalSelectorException
     *          If this channel was not created by the same provider
     *          as the given selector
     *
     * @throws  CancelledKeyException,如果通道已经注册到选择器,但是相关的SelectionKey已经被取消,
     抛出CancelledKeyException
     *          If this channel is currently registered with the given selector
     *          but the corresponding key has already been cancelled
     *
     * @throws  IllegalArgumentException
     *          If a bit in the <tt>ops</tt> set does not correspond to an
     *          operation that is supported by this channel, that is, if
     *          <tt>set & ~validOps() != 0</tt>
     *如果关注的事件ops是通道不支持的事件,则抛出IllegalArgumentException,我们
     可以通过set & ~validOps() != 0来判断,事件ops参数为否合法。
     * @return  A key representing the registration of this channel with
     *          the given selector
     */
    public abstract SelectionKey register(Selector sel, int ops, Object att)
        throws ClosedChannelException;
    //下面是,简单的通道注册到选择器的过程
    // sync(regLock) {
    //   sync(keySet) { look for selector }
    //   if (channel found) { set interest ops -- may block in selector;
    //                        return key; }
    //   create new key -- may block somewhere in selector;
    //   sync(keySet) { add key; }
    //   attach(attachment);
    //   return key;
    遍历选择的SelectionKey集合,查看通道是否存在,存在更新关注事件集,否则创建新的SelectionKey
    并添加到SelectionKey集合中。
    // }

    /**
     * Registers this channel with the given selector, returning a selection
     * key.
     *
     *  An invocation of this convenience method of the form
     *
     * <blockquote><tt>sc.register(sel, ops)</tt></blockquote>
     *
     * behaves in exactly the same way as the invocation
     *
     * <blockquote><tt>sc.{@link
     * #register(java.nio.channels.Selector,int,java.lang.Object)
     * register}(sel, ops, null)</tt></blockquote>
     *
     * @param  sel
     *         The selector with which this channel is to be registered
     *
     * @param  ops
     *         The interest set for the resulting key
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  ClosedSelectorException
     *          If the selector is closed
     *
     * @throws  IllegalBlockingModeException
     *          If this channel is in blocking mode
     *
     * @throws  IllegalSelectorException
     *          If this channel was not created by the same provider
     *          as the given selector
     *
     * @throws  CancelledKeyException
     *          If this channel is currently registered with the given selector
     *          but the corresponding key has already been cancelled
     *
     * @throws  IllegalArgumentException
     *          If a bit in <tt>ops</tt> does not correspond to an operation
     *          that is supported by this channel, that is, if <tt>set &
     *          ~validOps() != 0</tt>
     *
     * @return  A key representing the registration of this channel with
     *          the given selector
     */
    public final SelectionKey register(Selector sel, int ops)
        throws ClosedChannelException
    {
       //委托给 register(Selector sel, int ops, Object att)
        return register(sel, ops, null);
    }

    /**
     * Adjusts this channel's blocking mode.
     *调整通道的阻塞模式
     * <p> If this channel is registered with one or more selectors then an
     * attempt to place it into blocking mode will cause an {@link
     * IllegalBlockingModeException} to be thrown.
     *如果通道已经注册到选择器,尝试将通道设置为阻塞模式将抛出IllegalBlockingModeException,
     即注册到选择器的通道必须是非阻塞的。
     * <p> This method may be invoked at any time.  The new blocking mode will
     * only affect I/O operations that are initiated after this method returns.
     * For some implementations this may require blocking until all pending I/O
     * operations are complete.
     *
     这个方法可以在任何时候调用。在方法返回时,新的阻塞模式将会影响到已经开始的操作。
     在一些实现版本中,可能需要阻塞到所有的已经开始的IO操作完成。
     * <p> If this method is invoked while another invocation of this method or
     * of the {@link #register(Selector, int) register} method is in progress
     * then it will first block until the other operation is complete. 

     *
     当前其他方法调用或者通道注册到选择器操作正在进行时,此方法调用将会阻塞,直到
     其他操作完成。
     * @param  block  If <tt>true</tt> then this channel will be placed in
     *                blocking mode; if <tt>false</tt> then it will be placed
     *                non-blocking mode
     *true为阻塞模式,false为非阻塞模式
     * @return  This selectable channel
     *返回一个可选择的通道
     * @throws  ClosedChannelException
     *          If this channel is closed
     *如果通道已经关闭,则抛出ClosedChannelException
     * @throws  IllegalBlockingModeException
     *          If <tt>block</tt> is <tt>true</tt> and this channel is
     *          registered with one or more selectors
     *当通道已经注册到选择器,设置通道为阻塞模式将会抛出IllegalBlockingModeException
     * @throws IOException
     *         If an I/O error occurs
     */
    public abstract SelectableChannel configureBlocking(boolean block)
        throws IOException;
    //设置阻塞模式的简单示例
    // sync(regLock) {
    //   sync(keySet) { throw IBME if block && isRegistered; }
    //   change mode;
    // }

    /**
     * Tells whether or not every I/O operation on this channel will block
     * until it completes.  A newly-created channel is always in blocking mode.
     *判断通道上的每一个IO操作是否为阻塞模式,直到操作完成。一个新创建的通道为阻塞模式。
     *  If this channel is closed then the value returned by this method is
     * not specified. 

     *如果通道已经关闭,返回值是不确定
     * @return <tt>true</tt> if, and only if, this channel is in blocking mode
     */
    public abstract boolean isBlocking();

    /**
     * Retrieves the object upon which the {@link #configureBlocking
     * configureBlocking} and {@link #register register} methods synchronize.
     * This is often useful in the implementation of adaptors that require a
     * specific blocking mode to be maintained for a short period of time.
     * 
     *返回#configureBlocking和#register方法的同步对象。
     * @return  The blocking-mode lock object
     */
    public abstract Object blockingLock();

}

总结:
SelectableChannel是一个可选择的通道,可以注册到选择器,通道在创建时为阻塞模式,必选先通过configureBlocking方法,设置通道为非阻塞模式,才可以注册到注册器。我们可以通过validOps方法验证通道注册到选择器的事件,是否为通道支持的事件,可以通过isRegistered方法判断是否注册到选择器,用isBlocking方法判断通道是否为阻塞模式,用register方法将通道感兴趣的事件注册到选择器中,并返回一个注册器SelectionKey。

猜你喜欢

转载自donald-draper.iteye.com/blog/2369317