zoukankan      html  css  js  c++  java
  • Java 原生NIO

    Channel

    Channel管道是和IO操作对应的。 Channel 代表了针对io的一系列操作,无论这些io所属的类别(包括 磁盘io, 网络io 甚至是可以像io一样进行操作的程序组件,这里的io也是一种抽象)。

    Channel管道要么是开启open状态,要么是关闭closed状态。Channel创建之后就进入开启状态。在调用close方法后计入关闭状态。isOpen()方法可以获取Channel管道的开闭状态。

    Channel的设计意图上希望是对多线程安全的,继承和实现这个接口的类都应该按照这样的标准来实现。

    /**
     * A nexus for I/O operations.
     *
     * <p> A channel represents an open connection to an entity such as a hardware
     * device, a file, a network socket, or a program component that is capable of
     * performing one or more distinct I/O operations, for example reading or
     * writing.
     *
     * <p> A channel is either open or closed.  A channel is open upon creation,
     * and once closed it remains closed.  Once a channel is closed, any attempt to
     * invoke an I/O operation upon it will cause a {@link ClosedChannelException}
     * to be thrown.  Whether or not a channel is open may be tested by invoking
     * its {@link #isOpen isOpen} method.
     *
     * <p> Channels are, in general, intended to be safe for multithreaded access
     * as described in the specifications of the interfaces and classes that extend
     * and implement this interface.
     *
     *
     * @author Mark Reinhold
     * @author JSR-51 Expert Group
     * @since 1.4
     */
    
    public interface Channel extends Closeable
    

      

    NetworkChannel

    NetworkChannel 是针对网络io的管道。此接口通过bind(SocketAddress)方法来关联一个socket。setOption(SocketOption)和getOption(SocketOption)方法可以用来设置和查询socket操作。实现此接口的类应该表明它所能支持的操作类型。

    需要特殊说明的是,bind(SocketAddress) 和 setOption(SocketOption)方法的返回值就是这个NetworkChannel,从而它可以提供这样的代码风格:netchannel.bind(a).bind(b).setOption(x).setOption(y)。有的地方把这种风格成为lambda风格。

    /**
     * A channel to a network socket.
     *
     * <p> A channel that implements this interface is a channel to a network
     * socket. The {@link #bind(SocketAddress) bind} method is used to bind the
     * socket to a local {@link SocketAddress address}, the {@link #getLocalAddress()
     * getLocalAddress} method returns the address that the socket is bound to, and
     * the {@link #setOption(SocketOption,Object) setOption} and {@link
     * #getOption(SocketOption) getOption} methods are used to set and query socket
     * options.  An implementation of this interface should specify the socket options
     * that it supports.
     *
     * <p> The {@link #bind bind} and {@link #setOption setOption} methods that do
     * not otherwise have a value to return are specified to return the network
     * channel upon which they are invoked. This allows method invocations to be
     * chained. Implementations of this interface should specialize the return type
     * so that method invocations on the implementation class can be chained.
     *
     * @since 1.7
     */
    
    public interface NetworkChannel
        extends Channel
    

      

    SelectableChannel 

    SelectableChannel可用于多路复用的管道。 和selector一起使用的方式:先通过register(Selector, Object) 方法吧通道注册到复用器上,返回值SelectionKey就代表了这个注册关系。注册以后SelectableChannel处于注册状态,当它被反注册(取消注册)的时候,复用器Selector会吧Channel上分配的资源回收。而什么时候可以取消Channel的注册?当注册关系SelectionKey被Cancel方法取消的时候,Channel会被反注册。Channel自身无法反注册,他只能注册。

    当Channel所在线程中断或者调用了Channel的close方法,Channel管道就会被关闭。Channel管道关闭的时候,所有相关的SelectionKey也会被取消Cancel。

    使用isRegisted()方法可以判断Channel是否已经注册。isBlocking()方法表明了Channel管道是否是阻塞的。

    可复用管道SelectableChannel当然也是对多线程安全的。

    阻塞管道的io读写方法返回时, 数据是读写完毕的。非阻塞管道的io读写方法会立即返回,但不保证数据是读写完毕的,这个完毕是针对socket来讲的。

    新创建的SelectableChannel默认是处于阻塞状态。SelectableChannel 和 Selector 联合使用的时候,非阻塞状态才能发挥最大的作用。一般在使用的使用需要把SelectableChannel设置为非阻塞然后和Selector注册。需要注意的是:一定要在注册之前设置为非阻塞状态,并且管道是无法再转换成阻塞状态,直到管道被反注册。

    /**
     * A channel that can be multiplexed via a {@link Selector}.
     *
     * <p> 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.
     *
     * <p> 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.
     *
     * <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.
     *
     * <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.
     *
     * <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.
     *
     * <p> Selectable channels are safe for use by multiple concurrent
     * threads. </p>
     *
     *
     * <a name="bm"></a>
     * <h2>Blocking mode</h2>
     *
     * 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.
     *
     * <p> 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
    

      

    Selector

    Selector 是 SelectableChannel的多路复用器。创建Selector有两种方式:1,使用Selector的open()函数,该函数返回一个由默认的SelectorProvider创建的Selector复用器 ; 2,通过抽象类SelectorProvider的openSelector()方法来定制个性化的Selector,也就是继承SelectorProvider。一个Selector默认是处于开启状态,close函数可以关闭复用器。

    Selector和SelectableChannel之间的注册关系通过SelectionKey来表示。Selector主要维护三个注册集合(set of SelectionKeys):1,key set ; 2, selected-key set; 3, cancelled-key set

    1,key set , 可以使用Selector的keys()方法来获取这个集合。这个集合包含了注册到selector上的selectionKey

    2,selected-key set ,使用selectedKeys()来获取。如果一个key属于这个集合,那么说明这个key至少有一个关心的io操作可以进行。这个集合一定是key set 的一个子集。

    3, cancelled-key set,这个集合外部无法直接访问。如果一个key已经被cancel但是对应的管道没有反注册,那么这个key就被放置在此集合中。从这里也可以看出来:key的cancel和管道的deregistered不是同步的。这个集合一定是key set 的一个子集。

    在Selector刚创建的时候,这三个集合都是空的。那么这三个集合是在什么时候更新的?

    1,当Channel通过register(Selector, int)方法注册到selector上的时候,对应的key被添加到key set 中。selector进行 选择操作(selection operations)的时候,会把处于cancelled状态的key移出这个集合。

    2,当key被取消的时候,在下一次selector做选择操作的时候,会把key放入cancelled-key set 中, 同时,这个key也会从key set中移出。key被取消的时机前面也说过了,调用Channel的close或者Selectionkey的cancel

    3, selected-key set 这个集合比较特殊。它并不是在 selector的选择操作中更新的。一个key一般并不会直接加入这个集合中,从这个集合当中移出一个key可以使用集合的remove方法。可以先简单的理解,在抽象的io操作(server接受连接、client连接成功,数据可读,数据课写)中有特定(interested)的操作的时候,selected-key set 会被更新。

    Selector是多线程安全的。

    /**
     * A multiplexor of {@link SelectableChannel} objects.
     *
     * <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>
     *
     * <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>
     *
     *   <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>
     *
     *   <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>
     *
     *   <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>
     *
     * <p> All three sets are empty in a newly-created selector.
     *
     * <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.
     *
     * <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.
     *
     * <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>
     *
     * <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>
     *
     *   <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>
     *
     *   <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>
     *
     *     <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>
     *
     *     <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>
     *
     *   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.
     *
     *   <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>
     *
     * <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>
     *
     * <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.
     *
     * <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.
     *
     * <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.
     *
     * <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>
     *
     *   <li><p> By invoking the selector's {@link #wakeup wakeup} method,
     *   </p></li>
     *
     *   <li><p> By invoking the selector's {@link #close close} method, or
     *   </p></li>
     *
     *   <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>
     *
     * <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>
     *
     *
     * @author Mark Reinhold
     * @author JSR-51 Expert Group
     * @since 1.4
     *
     * @see SelectableChannel
     * @see SelectionKey
     */
    
    public abstract class Selector implements Closeable 
    

      

    SelectionKey

    这里捡要紧的说,废话就不多说了。SelectionKey,常见有两种操作,set(设置operations),test(检测操作);设置operations有两种方式:调用Channel的register方法时候设置, 或者 ,调用SelectionKey的interestOps(int)方法。注意,设置的operations必须是对应的channel关心的操作(interest)。通过SelectableChannel的validOps()函数可以查看channel关心的操作集合。设置validOps()意外的operation会导致运行时异常。

    SelectionKey的操作集合分为两类:1,interest set, 2,ready set。

    interest set 中的操作是Selector在selection选择操作中将要检测的操作集合。

    一个operation处于ready set 中,表明对应管道已经满足了进行这种操作的条件。SelectionKey的ready set 不能直接更新,它应该是在Selector的selection过程中更新。

    /**
     * A token representing the registration of a {@link SelectableChannel} with a
     * {@link Selector}.
     *
     * <p> A selection key is created each time a channel is registered with a
     * selector.  A key remains valid until it is <i>cancelled</i> by invoking its
     * {@link #cancel cancel} method, by closing its channel, or by closing its
     * selector.  Cancelling a key does not immediately remove it from its
     * selector; it is instead added to the selector's <a
     * href="Selector.html#ks"><i>cancelled-key set</i></a> for removal during the
     * next selection operation.  The validity of a key may be tested by invoking
     * its {@link #isValid isValid} method.
     *
     * <a name="opsets"></a>
     *
     * <p> A selection key contains two <i>operation sets</i> represented as
     * integer values.  Each bit of an operation set denotes a category of
     * selectable operations that are supported by the key's channel.
     *
     * <ul>
     *
     *   <li><p> The <i>interest set</i> determines which operation categories will
     *   be tested for readiness the next time one of the selector's selection
     *   methods is invoked.  The interest set is initialized with the value given
     *   when the key is created; it may later be changed via the {@link
     *   #interestOps(int)} method. </p></li>
     *
     *   <li><p> The <i>ready set</i> identifies the operation categories for which
     *   the key's channel has been detected to be ready by the key's selector.
     *   The ready set is initialized to zero when the key is created; it may later
     *   be updated by the selector during a selection operation, but it cannot be
     *   updated directly. </p></li>
     *
     * </ul>
     *
     * <p> That a selection key's ready set indicates that its channel is ready for
     * some operation category is a hint, but not a guarantee, that an operation in
     * such a category may be performed by a thread without causing the thread to
     * block.  A ready set is most likely to be accurate immediately after the
     * completion of a selection operation.  It is likely to be made inaccurate by
     * external events and by I/O operations that are invoked upon the
     * corresponding channel.
     *
     * <p> This class defines all known operation-set bits, but precisely which
     * bits are supported by a given channel depends upon the type of the channel.
     * Each subclass of {@link SelectableChannel} defines an {@link
     * SelectableChannel#validOps() validOps()} method which returns a set
     * identifying just those operations that are supported by the channel.  An
     * attempt to set or test an operation-set bit that is not supported by a key's
     * channel will result in an appropriate run-time exception.
     *
     * <p> It is often necessary to associate some application-specific data with a
     * selection key, for example an object that represents the state of a
     * higher-level protocol and handles readiness notifications in order to
     * implement that protocol.  Selection keys therefore support the
     * <i>attachment</i> of a single arbitrary object to a key.  An object can be
     * attached via the {@link #attach attach} method and then later retrieved via
     * the {@link #attachment() attachment} method.
     *
     * <p> Selection keys are safe for use by multiple concurrent threads.  The
     * operations of reading and writing the interest set will, in general, be
     * synchronized with certain operations of the selector.  Exactly how this
     * synchronization is performed is implementation-dependent: In a naive
     * implementation, reading or writing the interest set may block indefinitely
     * if a selection operation is already in progress; in a high-performance
     * implementation, reading or writing the interest set may block briefly, if at
     * all.  In any case, a selection operation will always use the interest-set
     * value that was current at the moment that the operation began.  </p>
     *
     *
     * @author Mark Reinhold
     * @author JSR-51 Expert Group
     * @since 1.4
     *
     * @see SelectableChannel
     * @see Selector
     */
    
    public abstract class SelectionKey
    

      

    总结

    高并发需要使用nio,它提供了单线程处理多io的能力。Java原生Nio中的主要概念是:channel,operation ,selectionKey,selector

    channel可以看做是对io流的封装,它不仅仅是简单的封装而已。还需要对应一些缓冲设置等。

    operation 抽象表示针对io流的一种操作,例如连接成功,流可写,流可读。

    selector是io操作的执行者,主要是他的selection方法。

    selectionKey表示channel和selector之间的关系。

  • 相关阅读:
    第七周-学习进度条
    《梦断代码》阅读笔记01
    第六周-学习进度条
    构建之法阅读笔记03
    结对项目开发(石家庄地铁乘车系统)
    第五周-学习进度条
    第四周-学习进度条
    HDU--1272 小希的迷宫(并查集判环与联通)
    HDU--1856 More is better(简单带权并查集)
    HDU--3635 带权并查集
  • 原文地址:https://www.cnblogs.com/afraidToForget/p/10071874.html
Copyright © 2011-2022 走看看