Selector & SelectionKey基础学习

netty技术内幕一(Selector,SelectionKey)

Java Nio注意事项 # selector

Selector类的使用(一)

SelectionKey类的使用

/*
package java.nio.channels;

import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.spi.SelectorProvider;
import java.util.Set;


/**
   =============================================
   channel的多路复用器
   =============================================
 * A multiplexor of {@link SelectableChannel} objects.


   =============================================
   1个selector可以通过调用Selector#open方法创建(使用系统默认实现),
   也可以通过SelectorProvider#open方法提供自定义的实现。
   selector会一直处于打开状态,一直到调用该selector#close方法
   =============================================
   
 * <p> A selector may be created by invoking the {@link #open open} method of
 * this class, which will use the system's default {@link
 * java.nio.channels.spi.SelectorProvider selector provider} to
 * create a new selector.  A selector may also be created by invoking the
 * {@link java.nio.channels.spi.SelectorProvider#openSelector openSelector}
 * method of a custom selector provider.  A selector remains open until it is
 * closed via its {@link #close close} method.
 *
 * <a name="ks"></a>

   =============================================
   当1个channel注册到selector时,就会得到1个SelectionKey来代表这个注册关系,
   1个selector维护了3个这个的SelectionKey的set集合
   =============================================   
 * <p> A selectable channel's registration with a selector is represented by a
 * {@link SelectionKey} object.  A selector maintains three sets of selection
 * keys:
 *
 * <ul>

   =============================================
   第1个是 key set 集合, 它代表了注册到当前selector的所有channel注册关系, 
   可以通过selector#key()方法返回
   =============================================
 *   <li><p> The <i>key set</i> contains the keys representing the current
 *   channel registrations of this selector.  This set is returned by the
 *   {@link #keys() keys} method. </p></li>

   =============================================
   第2个是 selected-key set集合, 它包含了通过上一次的查询操作, 
   当注册在该selector上的channel的任何感兴趣的事件已就绪时, 所对应的selectionKey。 
   可以通过调用Selector#selectedKeys()返回
   这个集合永远时key set集合的子集
   =============================================
 *   <li><p> The <i>selected-key set</i> is the set of keys such that each
 *   key's channel was detected to be ready for at least one of the operations
 *   identified in the key's interest set during a prior selection operation.
 *   This set is returned by the {@link #selectedKeys() selectedKeys} method.
 *   The selected-key set is always a subset of the key set. </p></li>

   =============================================
   第3个是 cancelled-key set集合, 它代表着所有被取消的SelectionKey, 
   但是这些被取消的key对应的channel还没有从selector上注销, 
   这个集合不能直接被访问,
   这个集合永远时key set集合的子集
   =============================================
 *   <li><p> The <i>cancelled-key</i> set is the set of keys that have been
 *   cancelled but whose channels have not yet been deregistered.  This set is
 *   not directly accessible.  The cancelled-key set is always a subset of the
 *   key set. </p></li>
 *
 * </ul>
 
   =============================================
   在新建的selector中, 这3个set集合都是空的
   =============================================
 * <p> All three sets are empty in a newly-created selector.

   =============================================
   当把1个channel注册到selector上时,就会得到1个SelectionKey来代表这个注册关系。
   被取消的key在查询操作期间, 才会从三个集合中移除掉。
   key set集合是不能被直接修改的。
   =============================================
 * <p> A key is added to a selector's key set as a side effect of registering a
 * channel via the channel's {@link SelectableChannel#register(Selector,int)
 * register} method.  Cancelled keys are removed from the key set during
 * selection operations.  The key set itself is not directly modifiable.


   =============================================
   无论是调用SelectionKey#cancel方法还是关闭channel, 其对应的SelectionKey都将会被添加到cancelled-key set集合中。
   但是这并不会使得对应channel立即从selector中注销, 而是在selector下一次作查询操作的时候, 这个channel才会从这个selector中注销, 
   并且注销的selectionKey将会从3个set集合中移除掉
   =============================================
 * <p> A key is added to its selector's cancelled-key set when it is cancelled,
 * whether by closing its channel or by invoking its {@link SelectionKey#cancel
 * cancel} method.  Cancelling a key will cause its channel to be deregistered
 * during the next selection operation, at which time the key will removed from
 * all of the selector's key sets.


   =============================================
   在selector的查询操作浅见, 会将发生感兴趣事件的SelectionKey添加到 slected-key 集合中,
   注意: 不能直接往slected-key 集合中添加SelectionKey.
   可以通过调用remove方法或者对应的迭代器的remove方法, 将某个selectionKey从slected-key 集合中移除
   =============================================
 * <a name="sks"></a><p> Keys are added to the selected-key set by selection
 * operations.  A key may be removed directly from the selected-key set by
 * invoking the set's {@link java.util.Set#remove(java.lang.Object) remove}
 * method or by invoking the {@link java.util.Iterator#remove() remove} method
 * of an {@link java.util.Iterator iterator} obtained from the
 * set.  Keys are never removed from the selected-key set in any other way;
 * they are not, in particular, removed as a side effect of selection
 * operations.  Keys may not be added directly to the selected-key set. </p>
 *
 *
 * <a name="selop"></a>
 * <h2>Selection</h2>


   =============================================
   在selector的每一次查询操作期间, 
   selectionKey可能被添加到selected-key集合当中,也可能从selected-key集合中移除,
   selectionKey也可能从key set集合中移除,
   selectionKey也可能从cancelled-key中移除。
   可以通过调用selector#select()、selector#select(long)、selector#selectNow()开启查询, 它包含3个步骤.
   =============================================
 * <p> During each selection operation, keys may be added to and removed from a
 * selector's selected-key set and may be removed from its key and
 * cancelled-key sets.  Selection is performed by the {@link #select()}, {@link
 * #select(long)}, and {@link #selectNow()} methods, and involves three steps:
 * </p>
 *
 * <ol>

   =============================================
   第一步: cancelled-key集合中的selectionKey从3个集合中全部移除掉, 对应的channel也从selector中注销掉,
   这个步骤会让cancelled-key集合变为空的
   =============================================
 *   <li><p> Each key in the cancelled-key set is removed from each key set of
 *   which it is a member, and its channel is deregistered.  This step leaves
 *   the cancelled-key set empty. </p></li>


   =============================================
   第二步: 底层操作系统会去查询剩余未被注销的channel是否发生了注册时所感兴趣的事件,
   当1个channel的任何1个感兴趣事件已就绪时, 会执行下面2个动作中的1个
   =============================================
 *   <li><p> The underlying operating system is queried for an update as to the
 *   readiness of each remaining channel to perform any of the operations
 *   identified by its key's interest set as of the moment that the selection
 *   operation began.  For a channel that is ready for at least one such
 *   operation, one of the following two actions is performed: </p>
 *
 *   <ol>

	   =============================================
	   如果这个channel的selectionKey还没有在selected-key集合中, 则它会被添加到这个集合中,
	   并且该selectionKey的就绪事件集被修改为channel当前已就绪事件集。
	   selectionKey之前的就绪集将会被丢弃。
	   =============================================
 *     <li><p> If the channel's key is not already in the selected-key set then
 *     it is added to that set and its ready-operation set is modified to
 *     identify exactly those operations for which the channel is now reported
 *     to be ready.  Any readiness information previously recorded in the ready
 *     set is discarded.  </p></li>

	   =============================================
	   如果这个channel的selectionKey已经在selected-key集合中, 之前的就绪事件集将会保留
	   =============================================
 *     <li><p> Otherwise the channel's key is already in the selected-key set,
 *     so its ready-operation set is modified to identify any new operations
 *     for which the channel is reported to be ready.  Any readiness
 *     information previously recorded in the ready set is preserved; in other
 *     words, the ready set returned by the underlying system is
 *     bitwise-disjoined into the key's current ready set. </p></li>
 *
 *   </ol>


     =============================================
     如果selector的key set集合中的所有SelectionKey在selector查询步骤开始的时候就没有任何感兴趣的事件,
     那么就不会更新selected-key集合, 也不会更新selectionKey中的任何就绪事件集
     =============================================
 *   If all of the keys in the key set at the start of this step have empty
 *   interest sets then neither the selected-key set nor any of the keys'
 *   ready-operation sets will be updated.

     =============================================
     如果每个key都被添加到了cacelled-key集合中, 那在第一步的时候就已经清空了
     =============================================
 *   <li><p> If any keys were added to the cancelled-key set while step (2) was
 *   in progress then they are processed as in step (1). </p></li>
 *
 * </ol>

   =============================================
   是等待1个channel感兴趣的事件就绪, 还是等待多个channel感兴趣的事件就绪, 等待多长时间是selector查询操作的这3个方法的区别
   =============================================   
 * <p> Whether or not a selection operation blocks to wait for one or more
 * channels to become ready, and if so for how long, is the only essential
 * difference between the three selection methods. </p>
 *
 *
 * <h2>Concurrency</h2>

   =============================================
   Selectors本身是线程安全的,但是他们的key set集合不是线程安全的
   =============================================   
 * <p> Selectors are themselves safe for use by multiple concurrent threads;
 * their key sets, however, are not.



 * <p> The selection operations synchronize on the selector itself, on the key
 * set, and on the selected-key set, in that order.  They also synchronize on
 * the cancelled-key set during steps (1) and (3) above.


   =============================================
   对selectionKey的感兴趣事件进行修改,不会立即生效,它将会在下一次查询操作时才会生效
   =============================================   
 * <p> Changes made to the interest sets of a selector's keys while a
 * selection operation is in progress have no effect upon that operation; they
 * will be seen by the next selection operation.


   =============================================
   key可能会在任何事件取消, channnel也可能在任何时间被关闭。
   因此,从selector中获取的key set集合并不意味着这些key都是有效的或者这些key对应的channel都是打开状态的,
   应用代码应该同步并且在必要的时候检查它们的状态, 以确定它们是否被取消或者被关闭了
   =============================================   
 * <p> Keys may be cancelled and channels may be closed at any time.  Hence the
 * presence of a key in one or more of a selector's key sets does not imply
 * that the key is valid or that its channel is open.  Application code should
 * be careful to synchronize and check these conditions as necessary if there
 * is any possibility that another thread will cancel a key or close a channel.

   =============================================
   1个线程调用selector#select()或者selector#select(long)方法可以通过其它线程使用以下的方式中断: 
   =============================================   
 * <p> A thread blocked in one of the {@link #select()} or {@link
 * #select(long)} methods may be interrupted by some other thread in one of
 * three ways:
 *
 * <ul>

   =============================================
   通过调用selector的wakeup方法
   =============================================   
 *   <li><p> By invoking the selector's {@link #wakeup wakeup} method,
 *   </p></li>

   =============================================
   通过调用selector的close方法
   =============================================   
 *   <li><p> By invoking the selector's {@link #close close} method, or
 *   </p></li>

   =============================================
   通过调用阻塞线程对象的interrupt方法, 在这种情况下, 线程会设置中断标记, 并且selector的wakeup()方法将会被调用
   =============================================   
 *   <li><p> By invoking the blocked thread's {@link
 *   java.lang.Thread#interrupt() interrupt} method, in which case its
 *   interrupt status will be set and the selector's {@link #wakeup wakeup}
 *   method will be invoked. </p></li>
 *
 * </ul>


 * <p> The {@link #close close} method synchronizes on the selector and all
 * three key sets in the same order as in a selection operation.
 *
 * <a name="ksc"></a>

   =============================================
   selector的key set集合与selected-key集合通常对多线程并发来说不是安全的。
   如果1个线程要直接修改这些set集合,应当要对这些set集合本身同步加锁。
   如果这个set集合在获取迭代器后,以任何除了调用迭代器本身的remove的方法修改了,那么会抛出并发修改异常,
   =============================================   	
 * <p> A selector's key and selected-key sets are not, in general, safe for use
 * by multiple concurrent threads.  If such a thread might modify one of these
 * sets directly then access should be controlled by synchronizing on the set
 * itself.  The iterators returned by these sets' {@link
 * java.util.Set#iterator() iterator} methods are <i>fail-fast:</i> If the set
 * is modified after the iterator is created, in any way except by invoking the
 * iterator's own {@link java.util.Iterator#remove() remove} method, then a
 * {@link java.util.ConcurrentModificationException} will be thrown. </p>
 *
 *
 *
 * @see SelectableChannel
 * @see SelectionKey
 */

public abstract class Selector implements Closeable {
    
    


    protected Selector() {
    
     }


    public static Selector open() throws IOException {
    
    
        return SelectorProvider.provider().openSelector();
    }

    // 返回 selector是否处于打开状态
    public abstract boolean isOpen();


    public abstract SelectorProvider provider();

    // 返回 selector的key set集合(注册的所有channel对应的SelectionKey)
    public abstract Set<SelectionKey> keys();

    // 返回 selector的key set集合(注册的所有channel对应的SelectionKey)
    public abstract Set<SelectionKey> selectedKeys();

    // 查询selector当前注册的channel感兴趣且已就绪的事件
    // 这个方法是非阻塞的。如果当前没有已就绪的事件,则返回0。
    // 调用此方法会消耗1次wakeup方法的调用
    public abstract int selectNow() throws IOException;

    // 查询selector当前注册的channel感兴趣且已就绪的事件
    // 这个方法是阻塞的,它会在如下的几种情况下停止阻塞:
    // 		1. 查询到至少1个channel的感兴趣且已就绪事件
    //      2. 调用了selector#wakeup方法
    //      3. 当前线程被中断
    //      4. 已过超时时间
    // 这个方法并不保证时间是对的,会有毫秒上的差异。
    // 指定的时间不应当为负数。如果是0,表示超时时间无限长。
    public abstract int select(long timeout) throws IOException;

    // 查询selector当前注册的channel感兴趣且已就绪的事件
     // 这个方法是阻塞的,它会在如下的几种情况下停止阻塞:
    // 		1. 查询到至少1个channel的感兴趣且已就绪事件
    //      2. 调用了selector#wakeup方法
    //      3. 当前线程被中断
    public abstract int select() throws IOException;

    // 调用此方法能让正处于查询状态的selector立即唤醒返回
    // 如果selector调用了select()或者select(long)处于阻塞状态, 调用此方法会让select方法立即返回。
    // 如果selector还未调用select()或者select(long)或者selectNow()前,就已经调用了wakeup,
    // 那么下一次调用这三个方法中的任何一个时,将会立即返回。
    // 在2个select()期间,调用此方法2次或多次,跟调用1次是一样的。
    // 作用类似于LockSupport#unpark()中的许可证。
    public abstract Selector wakeup();

    // 关闭selector
    // 如果selector正在select查询阻塞状态,那么它会停止阻塞,类似于调用了wakeup方法。
    // 任何未被取消的SelectionKey将会失效,对应的channnel也会注销掉,与此selector关联的其它资源也会被释放掉。
    // 再次调用此方法没有任何效果。
    // 关闭此selector后,除了调用wakeup方法外,调用任何其它的方法都将会抛出异常。
    public abstract void close() throws IOException;

}

猜你喜欢

转载自blog.csdn.net/qq_16992475/article/details/134749051