package java.nio.channels;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.io.IOException;
/**
* A token representing the registration of a {@link SelectableChannel} with a
* {@link Selector}.
*
SelectionKey表示一个可选择通道与选择器关联的注册器,可以简单理解为一个token。
* A selection key is created each time a channel is registered with a
* selector. A key remains valid until it is cancelled 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 * href="Selector.html#ks">cancelled-key set for removal during the
* next selection operation. The validity of a key may be tested by invoking
* its {@link #isValid isValid} method.
*
SelectionKey在每次通道注册到选择器时创建。SelectionKey在其调用取消方法,或自己的通道
关闭,或关联的选择器关闭之前,都是有效。取消一个SelectionKey,不会立刻从选择器移除;
而是在下一次通选器选择操作的过程,取消的SelectionKey从SelectionKey集合移除是无效的。
我们可以通过#isValid判断一个SelectionKey是否有效。
*
*
* represented as
* integer values. Each bit of an operation set denotes a category of
* selectable operations that are supported by the key's channel.
*
SelectionKey包含两个操作集,每个操作集用一个Integer来表示,int值中的低四位的bit
用于表示通道支持的可选操作种类。
* [list]
*
* The interest set 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.
*interest集合决定了选择器在下一个选择操作的过程中,操作事件是否是通道关注的。兴趣操作事件集
在SelectionKey创建时,初始化为注册选择器时的opt值,这个值可能通过interestOps(int)会改变。
* The ready set 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.
*ready集合表示通过选择器探测到通道已经准备就绪的操作事件。在SelectionKey创建时时,
就绪操作事件集值为0,在选择器的选择操作中可能会更新,但是不能直接的更新。
* [/list]
*
* 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.
*
SelectionKey的ready集合表示一个通道已经准备就绪的操作事件,但不能保证在没有引起线程
阻塞的情况下,就绪的操作事件会被线程执行。在一个选择操作完成后,就绪操作事件集,
大部分情况下回立即,更新。如果外部的事件或在通道有IO操作,就绪操作事件集可能不准确。
* 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.
*
SelectionKey定义了所有的操作事件,但是具体通道支持的操作事件依赖于具体的通道。
所有可选择的通道都可以通过validOps方法,判断一个操作事件是否被通道所支持。测试一个
不被通道所支持的通道,将会抛出相关的运行时异常。
*
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
* attachment 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.
*
如果需要经常关联一些应用的特殊数据到SelectionKey,比如一个object表示一个高层协议的
状态,object用于通知实现协议处理器。所以,SelectionKey支持通过attach方法将一个对象
附加的SelectionKey的attachment上。attachment可以通过#attachment方法进行修改。
*
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.
*
SelectionKey多线程并发访问时,是线程安全的。读写兴趣操作事件集的操作都将同步到,
选择器的具体操作。同步器执行过程是依赖实现的:在一个本地实现版本中,如果一个选择操作正在
进行,读写兴趣操作事件集也许会不确定地阻塞;在一个高性能的实现版本中,可能会简单阻塞。
无论任何时候,一个选择操作在操作开始时,选择器总是占用着兴趣操作事件集的值。
*
* @author Mark Reinhold
* @author JSR-51 Expert Group
* @since 1.4
*
* @see SelectableChannel
* @see Selector
*/
public abstract class SelectionKey {
/**
* Constructs an instance of this class.
*/
protected SelectionKey() { }
// -- Channel and selector operations --
/**
* Returns the channel for which this key was created. This method will
* continue to return the channel even after the key is cancelled.
*
返回SelectionKey关联的通道,即使在SelectionKey取消后,这个方法继续返回通道
* @return This key's channel
*/
public abstract SelectableChannel channel();
/**
* Returns the selector for which this key was created. This method will
* continue to return the selector even after the key is cancelled.
*
返回SelectionKey关联的选择器,即使在SelectionKey取消后,这个方法继续返回选择器
* @return This key's selector
*/
public abstract Selector selector();
/**
* Tells whether or not this key is valid.
*判断一个SelectionKey是否有效
* A key is valid upon creation and remains so until it is cancelled,
* its channel is closed, or its selector is closed.
*
在SelectionKey被取消,通道关闭或选择器关闭之前,SelectionKey都是有效的
* @return true if, and only if, this key is valid
*/
public abstract boolean isValid();
/**
* Requests that the registration of this key's channel with its selector
* be cancelled. Upon return the key will be invalid and will have been
* added to its selector's cancelled-key set. The key will be removed from
* all of the selector's key sets during the next selection operation.
*
取消SelectionKey关联的通道与选择器的注册器。取消后,key将无效,同时被添加到选择器的
取消SelectionKey集合,在选择器下一次选择操作中,将会被移除。
* If this key has already been cancelled then invoking this method has
* no effect. Once cancelled, a key remains forever invalid.
*
如果SelectionKey已经被取消,再次调用无效,一次取消,永久无效。
* This method may be invoked at any time. It synchronizes on the
* selector's cancelled-key set, and therefore may block briefly if invoked
* concurrently with a cancellation or selection operation involving the
* same selector.
方法可以在任何时候调用。将同步到选择器的cancelled-key集合中,如果调用时,
相关选择器正在取消或选择操作,则取消SelectionKey操作也许会简单的阻塞。
*/
public abstract void cancel();
// -- Operation-set accessors --
/**
* Retrieves this key's interest set.
*
获取SelectionKey的兴趣操作事件集interestOps
* It is guaranteed that the returned set will only contain operation
* bits that are valid for this key's channel.
*
操作保证返回的兴趣事件集中的事件是通道所支持的
* This method may be invoked at any time. Whether or not it blocks,
* and for how long, is implementation-dependent.
*
方法可以在任何时候调用,是否阻塞及阻塞多久,需要根据具体的实现。
* @return This key's interest set
*
* @throws CancelledKeyException
* If this key has been cancelled
如果SelectionKey已经被取消,则抛出CancelledKeyException
*/
public abstract int interestOps();
/**
* Sets this key's interest set to the given value.
*
设置兴趣操作事件集为指定的值
* This method may be invoked at any time. Whether or not it blocks,
* and for how long, is implementation-dependent.
*方法可以在任何时候调用,是否阻塞及阻塞多久,需要根据具体的实现。
* @param ops The new interest set
*
* @return This selection key
*
* @throws IllegalArgumentException
* If a bit in the set does not correspond to an operation that
* is supported by this key's channel, that is, if
* (ops & ~channel().validOps()) != 0
*如果所设置的操作事件集,有不被通道支持的事件,将抛出IllegalArgumentException
* @throws CancelledKeyException
* If this key has been cancelled
*/如果SelectionKey已经被取消,则抛出CancelledKeyException
public abstract SelectionKey interestOps(int ops);
/**
* Retrieves this key's ready-operation set.
*获取已经准备就绪的操作事件集
* It is guaranteed that the returned set will only contain operation
* bits that are valid for this key's channel.
*保证返回的就绪操作事件中的事件是通道所支持的
* @return This key's ready-operation set
*
* @throws CancelledKeyException
* If this key has been cancelled
*/
public abstract int readyOps();
// -- Operation bits and bit-testing convenience methods --
/**
* Operation-set bit for read operations.
*读操作事件
* Suppose that a selection key's interest set contains
* OP_READ at the start of a * href="Selector.html#selop">selection operation. If the selector
* detects that the corresponding channel is ready for reading, has reached
* end-of-stream, has been remotely shut down for further reading, or has
* an error pending, then it will add OP_READ to the key's
* ready-operation set and add the key to its selected-key set.
假设在选择器选择操作开始时,SelectionKey的兴趣操作事件集包含OP_READ事件。
如果选择器探测到相关的通道已经准备好读数据,已经到达流的末端,或流即将关闭,
或pend数据出错,选择器将会添加读操作事件到SelectionKey的就绪操作事件集,并
添加到可以选择的SelectionKey集。
*/
public static final int OP_READ = 1 << 0;
/**
* Operation-set bit for write operations.
*写操作事件
* Suppose that a selection key's interest set contains
* OP_WRITE at the start of a * href="Selector.html#selop">selection operation. If the selector
* detects that the corresponding channel is ready for writing, has been
* remotely shut down for further writing, or has an error pending, then it
* will add OP_WRITE to the key's ready set and add the key to its
* selected-key set.
假设在选择器选择操作开始时,SelectionKey的兴趣操作事件集包含OP_WRITE事件。
如果选择器探测到相关的通道已经准备好写数据,或流即将关闭,
或pend数据出错,选择器将会添加写操作事件到SelectionKey的就绪操作事件集,并
添加到可以选择的SelectionKey集。
*/
public static final int OP_WRITE = 1 << 2;
/**
* Operation-set bit for socket-connect operations.
*socket连接操作事件
* Suppose that a selection key's interest set contains
* OP_CONNECT at the start of a * href="Selector.html#selop">selection operation. If the selector
* detects that the corresponding socket channel is ready to complete its
* connection sequence, or has an error pending, then it will add
* OP_CONNECT to the key's ready set and add the key to its
* selected-key set.
假设在选择器选择操作开始时,SelectionKey的兴趣操作事件集包含OP_CONNECT事件。
如果选择器探测到相关的socket通道已经完成连接,或pend数据出错,选择器将会添加连接操作事件
到SelectionKey的就绪操作事件集,并添加到可以选择的SelectionKey集。
*/
public static final int OP_CONNECT = 1 << 3;
/**
* Operation-set bit for socket-accept operations.
*socket接受操作事件
* Suppose that a selection key's interest set contains
* OP_ACCEPT at the start of a * href="Selector.html#selop">selection operation. If the selector
* detects that the corresponding server-socket channel is ready to accept
* another connection, or has an error pending, then it will add
* OP_ACCEPT to the key's ready set and add the key to its
* selected-key set.
假设在选择器选择操作开始时,SelectionKey的兴趣操作事件集包含OP_ACCEPT事件。
如果选择器探测到相关的server-socket通道已经准备好接受另一个连接,
或pend数据出错,选择器将会添加OP_ACCEPT事件到SelectionKey的就绪操作事件集,
并添加到可以选择的SelectionKey集。
*/
public static final int OP_ACCEPT = 1 << 4;
/**
* Tests whether this key's channel is ready for reading.
*测试SelectionKey的通道是否准备好读操作事件
* An invocation of this method of the form k.isReadable()
* behaves in exactly the same way as the expression
*
*
* k.readyOps() & OP_READ != 0
If this key's channel does not support read operations then this
* method always returns false.
*
* @return true if, and only if,
* readyOps() & OP_READ is
* nonzero
*
* @throws CancelledKeyException
* If this key has been cancelled
*/
public final boolean isReadable() {
return (readyOps() & OP_READ) != 0;
}
/**
* Tests whether this key's channel is ready for writing.
*测试SelectionKey的通道是否准备好写操作事件
* An invocation of this method of the form k.isWritable()
* behaves in exactly the same way as the expression
*
*
* k.readyOps() & OP_WRITE != 0
If this key's channel does not support write operations then this
* method always returns false.
*
* @return true if, and only if,
* readyOps() & OP_WRITE
* is nonzero
*
* @throws CancelledKeyException
* If this key has been cancelled
*/
public final boolean isWritable() {
return (readyOps() & OP_WRITE) != 0;
}
/**
* Tests whether this key's channel has either finished, or failed to
* finish, its socket-connection operation.
*测试SelectionKey的socket通道连接操作是否完成
* An invocation of this method of the form k.isConnectable()
* behaves in exactly the same way as the expression
*
*
* k.readyOps() & OP_CONNECT != 0
If this key's channel does not support socket-connect operations
* then this method always returns false.
*
* @return true if, and only if,
* readyOps() & OP_CONNECT
* is nonzero
*
* @throws CancelledKeyException
* If this key has been cancelled
*/
public final boolean isConnectable() {
return (readyOps() & OP_CONNECT) != 0;
}
/**
* Tests whether this key's channel is ready to accept a new socket
* connection.
*测试SelectionKey的serversocket通道是否准备好接受一个新的socket的连接
* An invocation of this method of the form k.isAcceptable()
* behaves in exactly the same way as the expression
*
*
* k.readyOps() & OP_ACCEPT != 0
If this key's channel does not support socket-accept operations then This class tracks the validity of the key and implements cancellation. If this key has not yet been cancelled then it is added to its
* this method always returns false.
*
* @return true if, and only if,
* readyOps() & OP_ACCEPT
* is nonzero
*
* @throws CancelledKeyException
* If this key has been cancelled
*/
public final boolean isAcceptable() {
return (readyOps() & OP_ACCEPT) != 0;
}
// -- Attachments --
private volatile Object attachment = null;//附加对象
//原子更新SelectionKey的附加对象,负载Updater
private static final AtomicReferenceFieldUpdater
attachmentUpdater = AtomicReferenceFieldUpdater.newUpdater(
SelectionKey.class, Object.class, "attachment"
);
/**
* Attaches the given object to this key.
*将指定的对象设为附加对象
* An attached object may later be retrieved via the {@link #attachment()
* attachment} method. Only one object may be attached at a time; invoking
* this method causes any previous attachment to be discarded. The current
* attachment may be discarded by attaching null.
*
* @param ob
* The object to be attached; may be null
*
* @return The previously-attached object, if any,
* otherwise null
*/
public final Object attach(Object ob) {
return attachmentUpdater.getAndSet(this, ob);
}
/**
* Retrieves the current attachment.
*返回当前附加对象
* @return The object currently attached to this key,
* or null if there is no attachment
*/
public final Object attachment() {
return attachment;
}
}
[size=medium][b]
总结:[/b][/size]
[color=blue]SelectionKey表示一个可选择通道与选择器关联的注册器,可以简单理解为一个token。SelectionKey包含两个操作集,分别是兴趣操作事件集interestOps和通道就绪操作事件集readyOps,每个操作集用一个Integer来表示。interestOps用于选择器判断在下一个选择操作的过程中,操作事件是否是通道关注的。兴趣操作事件集在SelectionKey创建时,初始化为注册选择器时的opt值,这个值可能通过interestOps(int)会改变。SelectionKey的readyOps表示一个通道已经准备就绪的操作事件,但不能保证在没有引起线程阻塞的情况下,就绪的操作事件会被线程执行。在一个选择操作完成后,大部分情况下就绪操作事件集会立即更新。如果外部的事件或在通道有IO操作,就绪操作事件集可能不准确。如果需要经常关联一些应用的特殊数据到SelectionKey,比如一个object表示一个高层协议的状态,object用于通知实现协议处理器。所以,SelectionKey支持通过attach方法将一个对象附加的SelectionKey的attachment上。attachment可以通过#attachment方法进行修改。SelectionKey定义了所有的操作事件,但是具体通道支持的操作事件依赖于具体的通道。所有可选择的通道都可以通过validOps方法,判断一个操作事件是否被通道所支持。测试一个不被通道所支持的通道,将会抛出相关的运行时异常。SelectionKey多线程并发访问时,是线程安全的。读写兴趣操作事件集的操作都将同步到,选择器的具体操作。同步器执行过程是依赖实现的:在一个本地实现版本中,如果一个选择操作正在进行,读写兴趣操作事件集也许会不确定地阻塞;在一个高性能的实现版本中,可能会简单阻塞。无论任何时候,一个选择操作在操作开始时,选择器总是占用着兴趣操作事件集的值。SelectionKey可以简单理解为通道和选择器的映射关系,并定义了相关的操作事件,分别为OP_READ,OP_WRITE,OP_CONNECT,OP_ACCEPT值分别是,int的值的第四为分别为1,级1,4,8,16。用一个AtomicReferenceFieldUpdater原子更新attachment。
[/color]
附:
package java.nio.channels.spi;
import java.nio.channels.*;
/**
* Base implementation class for selection keys.
*
*
*
* @author Mark Reinhold
* @author JSR-51 Expert Group
* @since 1.4
*/
public abstract class AbstractSelectionKey
extends SelectionKey
{
/**
* Initializes a new instance of this class.
*/
protected AbstractSelectionKey() { }
//可见的选择key有效性
private volatile boolean valid = true;
//判断是否有效
public final boolean isValid() {
return valid;
}
//置选择key为无效
void invalidate() { // package-private
valid = false;
}
/**
* Cancels this key.
*
*
* selector's cancelled-key set while synchronized on that set.
取消选择key,如果选择key还没有完全取消,则同步到选择器的取消选择key集合中
*/
public final void cancel() {
// Synchronizing "this" to prevent this key from getting canceled
// multiple times by different threads, which might cause race
// condition between selector's select() and channel's close().
//同步this,为了阻止不同线程多次调用取消操作竞争,比如选择的选择操作和通道 //的关闭操作
synchronized (this) {
if (valid) {
valid = false;
//委托给选择器
((AbstractSelector)selector()).cancel(this);
}
}
}
}
在来看选择key的具体实现
class SelectionKeyImpl extends AbstractSelectionKey
{
final SelChImpl channel;//key关联的通道
final SelectorImpl selector;//key关联的选择器
private int index;//key索引(猜测不是通道的key集合索引,就是选择器的可集合索引)
private volatile int interestOps;//兴趣操作事件集
private int readyOps;//就绪操作事件集
//构造
SelectionKeyImpl(SelChImpl selchimpl, SelectorImpl selectorimpl)
{
channel = selchimpl;
selector = selectorimpl;
}
//返回key关联通道
public SelectableChannel channel()
{
return (SelectableChannel)channel;
}
//返回key关联的选择器
public Selector selector()
{
return selector;
}
//设置索引
int getIndex()
{
return index;
}
//设置索引
void setIndex(int i)
{
index = i;
}
//判断key是否有效
private void ensureValid()
{
if(!isValid())
throw new CancelledKeyException();
else
return;
}
//返回兴趣操作事件集
public int interestOps()
{
ensureValid();
return interestOps;
}
//设置兴趣操作事件集
public SelectionKey interestOps(int i)
{
ensureValid();
//实际设置兴趣操作事件集
return nioInterestOps(i);
}
//实际设置兴趣操作事件集
SelectionKey nioInterestOps(int i)
{
if((i & ~channel().validOps()) != 0)
{
//事件无效,抛出IllegalArgumentException
throw new IllegalArgumentException();
} else
{
//否则委托给通道,这个我们留在后面看
channel.translateAndSetInterestOps(i, this);
interestOps = i;
return this;
}
}
//返回兴趣操作事件集
int nioInterestOps()
{
return interestOps;
}
//返回就绪事件集
public int readyOps()
{
ensureValid();
return readyOps;
}
//设置就绪事件集
void nioReadyOps(int i)
{
readyOps = i;
}
//返回就绪事件集
int nioReadyOps()
{
return readyOps;
}
}
从SelectionKeyImpl的定义可以看出,SelectionKeyImpl关联一个可选择通道和选择器,
并实现了兴趣事件集和就绪事件集的设置和查询操作,其中readyOps和interestOps多了nio为前缀的方法,与无前缀的方法,基本无异,只是在nioInterestOps设置兴趣事件集是委托给了
具体的可选择通道的translateAndSetInterestOps方法。
再看一下SelChImpl选择通道的定义:
interface SelChImpl
extends Channel
{
//获取文件描述
public abstract FileDescriptor getFD();
public abstract int getFDVal();
//更新就绪事件集
public abstract boolean translateAndUpdateReadyOps(int i, SelectionKeyImpl selectionkeyimpl);
//设置就绪事件集
public abstract boolean translateAndSetReadyOps(int i, SelectionKeyImpl selectionkeyimpl);
//设置兴趣事件集
public abstract void translateAndSetInterestOps(int i, SelectionKeyImpl selectionkeyimpl);
public abstract int validOps();
public abstract void kill()
throws IOException;
}
选择key中的通道问什么是SelChImpl,我们看一下ServerSocketChannel的具体实现ServerSocketChannelImpl的定义,我们就会明白为什么是SelChImpl,
class ServerSocketChannelImpl extends ServerSocketChannel
implements SelChImpl
关于ServerSocketChannel为什么是ServerSocketChannelImpl,这个我们会在下一篇文章
SelectorProvider定义中,会说。
在SelChImpl接口定义中,我们看到 getFD返回的是FileDescriptor
再来看一下FileDescriptor是什么意思?好吧文章太长了,我们另开一篇再看。
FileDescriptor定义:[url]http://donald-draper.iteye.com/blog/2369957[/url]