选择器(Selector)基础

来源:互联网 发布:ubuntu无线网络共享 编辑:程序博客网 时间:2024/06/06 19:28

选择器基础

Selector、SelectableChannel、SelectionKey

    从基础的层面看,选择器提供了询问通道是否已准备好执行每个IO的能力。
    选择器类:管理一个被注册的通道集合的信息和它们的就绪状态。通道和选择器一起被注册的,并且使用选择器来更新通道的就绪状态。当这么做的时候,可以将被激发的线程挂起,直到有就绪的通道。
    可选择通道(SelectableChannel):该抽象类提供了实现通道的可选择性所需要的公共方法。它是所有支持就绪检查的通道类的父类。FileChannel是不可选择的(没有继承SelectableChannel),所有socket通道是可选择的,包括管道对象获得的通道。SelectableChannel可以被注册到Selector对象上。一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。

    选择键(SelectionKey):选择键封装了特定的通道与特定的选择器的注册关系。选择键对象被SelectableChannel.register( )返回并提供一个表示这种注册关系的标记。选择键包含了两个比特集(以整数的形式进行编码),指示了该注册关系所关心的通道操作,以及通道已经准备好的操作。

public abstract class SelectableChannel extends AbstractChannel implements Channel {     // This is a partial API listing     public abstract SelectionKey register (Selector sel, int ops)            throws ClosedChannelException;     public abstract SelectionKey register (Selector sel, int ops,            Object att)throws ClosedChannelException;     public abstract boolean isRegistered( );     public abstract SelectionKey keyFor (Selector sel);     public abstract int validOps( );     public abstract void configureBlocking (boolean block)           throws IOException;     public abstract boolean isBlocking( );     public abstract Object blockingLock( ); }

    regisit()方法会将它注册到一个选择器上。在一个出于阻塞状态的通道上注册,会抛出IllegalBlockingModeException异常,此外通道一旦被注册,就不能回到阻塞状态。

public abstract class Selector {     public static Selector open( ) throws IOException     public abstract boolean isOpen( );     public abstract void close( ) throws IOException;     public abstract SelectionProvider provider( );     public abstract int select( ) throws IOException;     public abstract int select (long timeout) throws IOException;     public abstract int selectNow( ) throws IOException;     public abstract void wakeup( );     public abstract Set keys( );     public abstract Set selectedKeys( ); }
    SelectableChannel类定义了register()方法,还是应该讲通道注册到选择器上。选择器维护了一个需要监控的通道集合。一个给定的通道可以被注册到多余一个选择器上,而且不需要知道它被注册到哪个Selector对象上。register()方法返回一个封装了两个对象的关系的选择键对象。选择器对象控制了被注册到它之上的通道的选择过程。
public abstract class SelectionKey {     public static final int OP_READ     public static final int OP_WRITE     public static final int OP_CONNECT     public static final int OP_ACCEPT     public abstract SelectableChannel channel( );     public abstract Selector selector( );     public abstract void cancel( );     public abstract boolean isValid( );     public abstract int interestOps( );     public abstract void interestOps (int ops);     public abstract int readyOps( );     public final boolean isReadable( )     public final boolean isWritable( )     public final boolean isConnectable( )     public final boolean isAcceptable( )     public final Object attach (Object ob)     public final Object attachment( ) }

    对于键的interest(感兴趣的操作)集合和ready(已经准备好的操作)集合的解释是和特定的通道相关的。

建立选择器

Selector selector = Selector.open( ); channel1.register (selector, SelectionKey.OP_READ); channel2.register (selector, SelectionKey.OP_WRITE); channel3.register (selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); // Wait up to 10 seconds for a channel to become ready readyCount = selector.select (10000); 

    该代码创建了一个新选择器,然后将socket通道注册到选择器上,且感兴趣的操作个不相同。select()方法将线程置于睡眠状态,知道感兴趣的操作有一个发生或10秒的时间过去。
    看Selector的API,Selector对象是通过调用静态工厂方法open( )来实例化的。类方法open()想spi发出请求,通过默认的SelectorProvider对象获取一个新的实例。可以通过调用provider()来决定由哪个SelectorProvider对象来创建给定的Selector实例。
    不在使用Selector时,调用close()方法来释放它占用的资源以及设置选择键无效。

     看SelectableChannel的API,register( )方法接受一个Selector对象作为参数,以及一个名为ops的整数参数。第二个参数表示所关心的通道操作。这是一个表示选择器在检查通道就绪状态时需要关心的操作的比特掩码。
    有四种被定义的可选择操作:读(read),写(write),连接(connect)和接受(accept)。并非所有的操作都在所有的可选择通道上被支持。例如,SocketChannel不支持accept。调用validOps( )方法来获取特定的通道所支持的操作集合。
    选择器包含了注册到它们之上的通道的集合,在任意给定的时间里,对于一个给定的选择器和一个给定的通道而言,只有一种注册关系是有效的。但是,将一个通道注册到多于一个的选择器上允许的,这么做的话,在更新interest集合为指定的值的同时,将返回与之前相同的选择键。
    register( )的第二个版本,这个版本接受object参数。可以传递您提供的对象引用,在调用新生成的选择键的attach( )方法时会将这个对象引用返回给您、
    一个单独的通道对象可以被注册到多个选择器上。可以调用isRegistered( )方法来检查一个通道是否被注册到任何一个选择器上,但没有提供关于通道被注册到哪个选择器上的信息,而只能知道它至少被注册到了一个选择器上。
    keyFor( )方法将返回与该通道和指定的选择器相关的键,如果通道被注册到指定的选择器上,那么相关的键将被返回。如果它们之间没有注册关系,那么将返回null。




原创粉丝点击