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。