首先来看下文档描述linux
一个就是直接调用open方法windows
public static Selector open() throws IOException { return SelectorProvider.provider().openSelector(); }
或者调用选用某个SelectorProvider的openSelector安全
public abstract AbstractSelector openSelector()
一个Selector有3种SelectionKey集合并发
一种就是所有注册的SelectionKey集合,即keys()方法返回的结果socket
一种就是活跃的SelectionKey集合,即selectedKeys()方法返回的结果ide
第三种就是已取消的SelectionKey集合,这些已被取消可是还未从Selector取消注册oop
再确认下下面的几个问题:.net
什么叫注册线程
即将一个channel感兴趣的事件注册到Selector上,即以下方法设计
SelectionKey register(AbstractSelectableChannel ch, int ops, Object att)
对于select、poll的Selector实现:仅仅是保存上述AbstractSelectableChannel感兴趣的ops到指定地方
对于epoll的Selector实现:则是执行系统调用epoll_ctl方法,操做参数是EPOLL_CTL_ADD
什么叫取消
就是调用SelectionKey的cancel方法,该方法的实现是,将该SelectionKey放入cancelledKeys而已,没有作其余操做
什么叫取消注册
取消注册,就是从Selector从释放出来再也不关注某个事件。一般在咱们的select过程当中就会遍历上述cancelledKeys,依次执行取消注册的行为。不一样的Selector有不一样的行为,如epoll则是执行系统调用epoll_ctl方法,操做参数是EPOLL_CTL_DEL。
分别以下:
int select():表示一直阻塞到有事件为止 int select(long timeout):最多阻塞timeout时间 int selectNow():不阻塞,检查结果后当即返回
Selector不是线程安全的,不过大部分状况都是一个线程拥有一个Selector,因此不须要它线程安全。
以ZooKeeper为例,代码简述以下
final Selector selector = Selector.open(); public void run() { while (!ss.socket().isClosed()) { try { selector.select(1000); Set<SelectionKey> selected = selector.selectedKeys(); for (SelectionKey k : selected) { if ((k.readyOps() & SelectionKey.OP_ACCEPT) != 0) { //执行accept链接的事件 SocketChannel sc = ((ServerSocketChannel) k .channel()).accept(); sc.configureBlocking(false); SelectionKey sk = sc.register(selector, SelectionKey.OP_READ); NIOServerCnxn cnxn = createConnection(sc, sk); sk.attach(cnxn); addCnxn(cnxn); } else if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) { //执行IO读写事件 NIOServerCnxn c = (NIOServerCnxn) k.attachment(); c.doIO(k); } else { //未知 } } selected.clear(); } catch (RuntimeException e) { LOG.warn("Ignoring unexpected runtime exception", e); } catch (Exception e) { LOG.warn("Ignoring exception", e); } } closeAll(); LOG.info("NIOServerCnxn factory exited run method"); }
while循环里面不断调用selector.select(1000)方法,而后经过selector.selectedKeys()来获取到有事件的SelectionKey集合,即上述提到的活跃的SelectionKey集合。而后遍历该集合,执行对应的事件。
目前Selector目前有以下实现
针对linux平台的实现:
针对windows平台的实现:
而Netty的NioEventLoop则是使用上述linux平台的实现PollSelectorImpl。Netty本身提供了另一种epoll实现,没有直接采用上述jdk自带的EPollSelectorImpl。
接下来就要开始重点说说jdk的poll是怎么实现的,即PollSelectorImpl的内容