Selector是什么
- Selector是一个或多个SelectableChannel对象的多路复用器.
如何创建一个Selector对象
- 一个
selector对象可以通过调用Selector.open()来创建,这个工厂方法会使用系统默认的selector provider来创建一个新的selector对象。或者我们还可以通过实现抽象类SelectorProvider自定义一个selector provider,调用new SelectorProviderImpl().openSelector()来创建它。 - 除非调用selector.close(),否则该
selector将会一直保持打开状态。
如何将selectable channel注册到selector中
SelectionKey key = channel.register(selector,Selectionkey.XXX);
- 通过
channel的register方法,将channel注册到给定的selector中,并返回一个表示注册关系的SelectionKey 对象。
selector如何维护selection keys
-
一个
selector维护着三个selection keys集合:-
key set 包含着所有
selectionKeys,当前所有注册到selector中的channel返回的注册关系SelectionKey都包含在内,这个集合可以通过selector.keys() 方法返回。 -
selected-key set 包含着一部分
selectionKeys,其中的每个selectionKey所关联的channel在selection operation期间被检测出至少准备好了一个可以在兴趣集中匹配到的操作。这个集合可以通过调用selector.selectedKeys()方法返回。selected-key set 一定是 key set 的子集。 -
cancelled-key set 也包含着一部分
selectionKeys,其中的每个selectionKey都已经被取消,但是所关联channel还没有被撤销登记。cancelled-key set 不能够被直接返回,但也一定是 key set 的子集。
对于一个新创建的
selector其中这三个集合都是空着的。通过
channel的register方法,一个selectionKey被增加到selector的 key set 中。无论通过channel.close()还是通过selectionKey.cancel()来
取消一个selectionKey,这个selectionKey都会被立即添加到selector的 cancelled-key set 中,但是所关联的channel并没有立即被撤销登记,直到发生下次selection operations, 这些channel才被从selector中撤销登记,与此同时这些Cancelled keys才会被从这个selector的所有selectionKey set(可能是_key set_、selected-key set、cancelled-key set)中移除,但是不会影响这些集合本身。在
selection operations期间,一些selectionKey会被选中添加到 selected-key set 中。其中的每个key可以通过selectiedKeys.remove()或selectiedKeys.iterator().remove()直接从 selected-key set 中移除,除此之外不能够通过任何方式被直接移除。特殊的,selected-key set 中的keys还可以在selection operations期间被间接移除。但是是不可以直接向 selected-key set 添加key的。 -
selector如何选择就绪channel
- 每次
selection operation期间, keys都可以从selector's selected-key set 被添加或者移除,同时也可以从它的 key 和 cancelled-key sets 被移除。selection operation可以被触发通过执行selector.select(),selector.select(long),和selector.selectNow() 方法,并且这些方法涉及到以下三个步骤:
首先每个位于 cancelled-key set 中的
key会从每个包含它的key集合中被移除,并且对应的channel会被撤销登记。这个步骤使得 cancelled-key set 变为空。查询底层操作系统来获得关于
selector中剩余channel的就续事件从selection operation开始截止到此刻的更新情况,只要哪个channel的就续事件的更新部分有至少一个与兴趣集中的操作匹配上,那么将会执行以下两个动作:
如果这个
channel's key没有存在于 selected-key set 那么将它添加到这个集合中,并将它的就绪操作集(ready-operation set)修改成只包含使得channel被报告就绪的操作,任何先前记录在就绪操作集中的就绪信息都会被丢弃。否则,如果这个
channel's key存在于 selected-key set ,那么就保留就绪操作集中先前的就绪信息,并将这些 使得channel被报告就绪的操作 写入进去;总而言之,系统底层会通过按位与&操作更新当前就绪集。如果这些
Key的兴趣集为空,那么 selected-key set 和 keys'的就续集(ready-operation sets)都不会被更新。如果在步骤(2)正在进行时将任何
key添加到 cancelled-key set,则按步骤(1)处理它们。
selection operations是否会阻塞等待一个或多个通道准备就绪,以及等待多长时间,这是三种选择方法之间唯一的本质区别。
selector线程安全吗
多线程并发情况下Selectors本身是线程安全的,但是他们所持有的key sets不是线程安全的。
selection operations 按顺序在selector本身,key set 和 selected-key set 上同步。 它们还在上面的步骤(1)和(3)期间在 canceled-key set 上同步。
在 selection operations 期间改变key的兴趣集,对于本次操作将不会产生任何影响;它们的影响将会再下次 selection operations 期间发生。
selectionKey可能会被取消,channel可能随时关闭。 因此,在一个或多个选择器的key集中存在并不意味着selectionKey有效或其channel是开放的。有可能另一个线程取消selectionKey或关闭一个channel,应用程序代码应该小心地同步并检查这些条件。
一个线程通过selector.select()或selector.select(long)方法产生的阻塞可以被其他线程用以下三种方式的任意一种来中断:
-
By invoking the selector's wakeup() method,
-
By invoking the selector's close() method, or
-
By invoking the blocked thread's interrupt() method, in which case its interrupt status will be set and the selector's wakeup() method will be invoked.
selector.close() 在 selection operations 期间会顺序的同步selectorand all three key sets 。
一个selector的 key set 和 selected-key set 通常情况下是线程不安全的。如果一个线程想要修改这个集合,需要同步控制它。通过key集合的iterator()方法返回的Iterators提供了快速失败(fail-fast):如果在创建迭代器之后修改了set,除了通过调用迭代器自己的remove() 方法之外,将抛出ConcurrentModificationException 。