zoukankan      html  css  js  c++  java
  • 浅析Java Nio 之 选择器

    浅析Java Nio 之 选择器


    Selector

    Selector是SelectableChannel的多路复用器。Selector可以通过静态工厂方法open调用系统默认的selector provider来创建,也可以通过自定义的SelectorProvider调用openSelector方法创建。直到调用close方法之前,selector会一直保持打开状态。
    SelectableChannel可以调用register方法注册Selector中,同时可以指定selector感兴趣的操作,SelectionKey封装了Selector和SelectableChannel的注册关系信息。如果channel是阻塞的,将会抛出IllegalBlockingModeException,而且通道注册之后,不能调用configureBlocking方法回到阻塞状态。
    Selector包含了三个选择键的集合,在刚创建的时候都是空的。

    • keys方法返回与selector关联的选择键集合。该集合包括当前通道在selector上注册的选择键。
    • selectedKeys方法返回Selector的已选择键集合,它包含相关通道被选择器判断已经准备好的,并且包含于key的interest集合中的操作,它是已注册的键集合的子集合,每个键都关联一个已经准备好至少一个操作的通道,每个键都持有一个内嵌的ready集合,指示了所关联的通道已经准备好的操作。
    • 已取消的键的集合,包含了调用cancel方法的选择键的集合,但还没有被注销,是已注册的键的集合的子集,它是selector对象的私有成员,无法直接访问。

    SelectableChannel注册selector时会添加key到key set中。select操作时会将cancell key从key set中删除,key set自身不能直接修改。
    当SelectionKey调用cancell方法或者channel关闭的时候会添加到对应的selector的cancelled-key set中,一旦SelectionKey无效了,调用与它相关的方法将会抛出CancelledKeyException。
    cancell一个键将导致在下一次的select操作中将对应通道从selector取消注册,同时SelectionKey会从所有的选择键集合中删除。
    通过select操作,就绪的SelectionKey会被添加到selected-key set中去,selectionKey可以通过通过key set 的remove方法或者iterator进行迭代的时候调用remove方法将selectionKey从set中remove,除此之外,不能通过其他方式remove SelectionKey,同样,selectionKey也不能直接添加到已选择键集合中。

    Selection

    在每一次都select操作中,Selector的已选择键集合都会删除或者添加对应的selectionKey或者从已取消键的集合中删除,Selection操作可以通过select(),select(time)或者selectNow()方法进行调用。

    Selection过程

    • 检查已取消键的集合,在已取消键的集合中每一个成员都会其他两个集合中移除,并且对应的通道都会注销,这一步执行完成之后,已取消键集合将会清空。

    • selection操作开始的时候,底层操作系统会去查询更新,剩下的每一个通道的准备执行的操作是否已经就绪(已注册选择键集合的SelectionKey中的感兴趣集合的操作)。系统调用过程可能会使得调用线程睡眠一段时间,对于那些没有准备好的通道不会进行任何的操作,而那些在这次Selection操作中已经准备好了的interest操作的通道,将会执行下列两种操作之一:

      • 如果通道的键并没有处于已选择的键的集合中,那么就会将他们加入到集合中。那些通道中已经准确确认已经准备好的操作会被添加到Selectionkey的已准备的集合中。同时操作系统会发现当前通道已经准备好的操作的信息将会被撤销。
      • 否则,如果通道的键处于已选择键的集合中,SelectionKey的已准备的集合会被修改成通道已经确认准备好操作的集合,之前在已准备集合的记录的就绪信息会被累积。也就是说由操作系统决定的已准备集合是与之前的已准备集合是按位分离的,一旦键被放置于选择器的已选择的键的集合中,它的已准备集合是累积的。
    • 当步骤二在执行的时候,与选择器相关的键可能会被取消,当步骤二结束的时候,步骤一会重新执行,来完成任意一个在选择进行的过程中,将已取消的通道的注销。

    • Selection操作返回的值是已准备集合中在步骤二过程被修改的SelectionKey的数量,而不是已选择键的集合中通道的数目。返回的值不是已经准备好的通道的总数,而是从上一次selection调用之后进入就绪状态的通道的数目。

    • 这三种selection操作,仅仅是在它们所注册的通道当前没有就绪的时候,是否阻塞有所区别,其他地方并没有区别。

    并发性

    Selector在多线程环境使用是线程安全的,但是他们的选择键集合并不是。通过keys()和selectKeys()方法返回的选择键集合是Selector对象内部私有的Set对象集合的引用。已注册的选择键集合应该是只读的,如果试图去修改它,将会抛出UnsupportededOperationException。在Selection过程中,Selector对象进行自身进行同步,然后是已注册的选择键集合、已选择的选择键集合,按照这样的顺序,已取消的键的集合在选择的过程的第一步和第三步保持同步(当与取消的选择键的集合相关的通道被注销时)。在Selection过程中对感兴趣的集合的修改不会被当前调用过程产生影响,他们会在下一次的selection过程生效。在任何时候,都可以取消选择键跟关闭通道。因此在选择键集合的键并不意味着选择键是合法的或者通道还在打开。
    因此,我们需要注意同步跟检查是否存在其他线程进行取消键跟关闭通道的可能。因此,除非使用同步,否则键的状态和相关的通道在任何时候都会发生改变,一个特定的键的集合的一个键并不能保存是有效的或者通道仍然打开。如果使用一个已经失效的键,将会抛出CancelledKeyException,如果使用已经关闭的通道,将会导致ClosedChannelException。通道提供了异步关闭的能力,当一个通道关闭的时候,它相关的键都会被取消。不过不会影响正在进行的selection操作,防止出现一个线程在关闭一个正在进行Selection操作的通道的时候,被阻塞与无限的等待的可能。同样,我们应该通过selectkeys方法来获取已经选择的键的集合,而不是自己主动去维护选择键的集合。
    线程在执行Selection操作的时候可能会被其他线程调用以下方法给中断

    • Selector的wakeup方法
    • Selector的close方法
    • 阻塞线程的interrupt方法会导致线程的中断标志位被设置跟wakeup方法调用。

    Selector的close方法跟select方法的同步方式是一样的,因此也存在阻塞的可能。在selection的过程中,如果调用close方法会被阻塞,直到selection过程结束,或者调用select方法的线程睡眠。

    如果你想在多线程并发的环境共享SelectionKey或者选择键集合,因为iterator是fail-fast的,如果在迭代过程中,Set对象的结构发生了变化,将会抛出concurrentModificationException异常。

  • 相关阅读:
    信息 信息熵 信息增益
    数据挖掘导论
    拆包粘包问题的解决方案
    杂物
    《深入理解计算机系统》
    Flex布局
    jquery常用的选择器
    jdk源码阅读优先级
    js和jquery页面初始化加载函数的方法及先后顺序
    SpringBoot定时器任务,每月一号执行
  • 原文地址:https://www.cnblogs.com/xianyijun/p/5422727.html
Copyright © 2011-2022 走看看