class="java">import java.io.Closeable; import java.io.IOException; import java.nio.channels.spi.SelectorProvider; import java.util.Set; /** * * A multiplexor of {@link SelectableChannel} objects. * <pre> * Selector * ^ * ________________________|________________________________ * | | | | * ... SelectionKey SelectionKey ... * | | * ... SelectableChannel SelectableChannel ... * * * 以下两种创建方式: * 1.调用Selector.open() * 2.调用java.nio.channels.spi.SelectorProvider.openSelector() * * 有三种key set: * 1.registered key set. 已注册的键集 * 2.selected key set, 已选择的键集, 之中每一个key的channel都至少准备好一种操作 * 3.cancelled key set, 已取消的键集, 调用SelectionKey.cancel()后, 那个SelectionKey * 就被加到这里, 在下一次select()/selectNow()/select(long)时, 该SelectionKey就会被移除. * <p> * select()/selectNow()/select(long)的过程: * 1.cancelled key set中的每个key都会从另两个key set中移除, 对应的通道也被注销, cancelled key set被清空。 * 2.registered key set 中的key的inters集合将被检查, 在这个步骤中的检查执行完后, 对interst集合更改不会影响接下来的过程, * 接下来底层操作系统将进行查询, 以确定每个通道所关心的操作的真是就绪状态.系统调用完成后, 对那些还没准备好的通道将不会执行任何操作, * 对那些已准备好的通道, 将执行以下两种操作之一: * * a.如果通道的键还没有处于已选择的键的集合, 那么键的ready集合将被清空, 然后表示操作系统发行的但钱通道已经准备好的操作的比特掩码将被设置. * * b.否则, 也就是在已选择的键的集合中, 键的ready集合将被表示操作系统发现的当前已经准备好的操作的比特掩码更新。所有之前的已经不再是就绪状 * 态的操作不会被清除.事实上, 所有的比特位都不会被清理,由操作系统决定的ready集合是与之前的ready集合按位分离的, 一旦键被放置于选择器的 * 已选择的键的集合中, 他的ready集合将是累积的,比特位只会被设置, 不会被清理. * 3.步骤2发生过程中, 有可能有些键被取消了, 因此在步骤2执行完后步骤1将再次执行, 以确保键已经被取消的通道的注销 * 4.select操作返回的值是ready集合在步骤2中被修改的键的数量, 而不是已选择的键的集合中的通道的数量. 返回值不是已准备好的通道的总数, 而是 * 是从上一个select()调用之后进入就绪状态的通道的数量。之前的调用中就绪的, 并且在本次调用中依然就绪的不会被计入, 而那些在前一次调用中已经 * 就绪但现在已经不处于就绪的通道也不会被计入,这些通道可能仍然在已选择的键的集合中, 但不会被计入返回值. *</p> *<p> * 有三个选择的方法select()、select(long)和selectNow(), 前两个会阻塞当前线程, 而在这阻塞过程中, 有三种方法可以使线程退出阻塞状态: * 1.Selector.wakeup()方法, 使选择器上的第一个还没有返回的选择操作立即返回,如果当前没有进行中的选择操作, 那下一次select()方法的一种 * 形式的调用将立即返回. 后面的选择操作正常执行 * 2.Selector.close()方法. 任何一个在选择操作中阻塞的线程都将被唤醒, 与选择器相关的通道将被注销, 而键被取消 * 3.Thread.currentThread.interrupt(), 该阻塞是可以响应中断的. * * </p> * </pre> */ public abstract class Selector implements Closeable { protected Selector() { } /** * Opens a selector. */ public static Selector open() throws IOException { return SelectorProvider.provider().openSelector(); } /** * Tells whether or not this selector is open. */ public abstract boolean isOpen(); /** * Returns the provider that created this channel. */ public abstract SelectorProvider provider(); /** * Returns this selector's registered-key set. */ public abstract Set<SelectionKey> keys(); /** * Returns this selector's selected-key set. */ public abstract Set<SelectionKey> selectedKeys(); /** * Selects a set of keys whose corresponding channels are ready for I/O * operations.不会阻塞 */ public abstract int selectNow() throws IOException; /** * Selects a set of keys whose corresponding channels are ready for I/O * operations.可能阻塞, 但最多阻塞 timeout ms */ public abstract int select(long timeout) throws IOException; /** * Selects a set of keys whose corresponding channels are ready for I/O * operations.可能阻塞, 直到底层系统调用完成 */ public abstract int select() throws IOException; /** * Causes the first selection operation that has not yet returned to return * immediately. */ public abstract Selector wakeup(); /** * Closes this selector. */ public abstract void close() throws IOException; }
?