在JDK1.4.2中加入了对NIO的支持,掌握其中的Selector个人认为是能实现好NIO的关键。
Selector是用来获取注册在其中的channel的相关事件的发生,也就是accept,read和write。selector中有3个key set。
key set:包含代表所有在其中注册的channel,可以通过selector.keys()得到。
selected-key set:包含所有被检测到有关注的操作已经就绪的key,通过selector.selectedKeys得到。
cancelled-key set:包含所有已经被cancel,但是还没有channel还没有deregister的key,这个集合是不能直接被访问的。
key通过调用channel的register方法被加入到key set中。被取消的key在select的时候会被从相应的key set中移除。
key set自身是不可以直接进行修改的。 无论是通过调用channel的close方法还是调用key的cancel方法,key都会被放置到canceled-key set中。取消的key会将其channel在下一次select时将注册撤销,同时将key从所有的key set中移除。
key在执行select操作时被加入到selected-key set中。在selected-key set中的key可以通过调用iterator的remove方法,将其从selected-key set中移除,不能通过其他的办法将其从selected-key set中移除。
通过selector的3个方法select(阻塞选择,直到有关心的事件发生时退出阻塞),selectNow(不阻塞选择),select(long)(指定超时选择,超时到达或者有关心事件发生时退出阻塞),来获取关心事件的发生。其执行步骤分为以下3步:
1、将存在于canceled-key set中的key从所有的key set中移除,撤销注册的channel,清空canceled-key set。
2、地层操作系统检查是否有关心的事件发生,当有关心的事件发生时,首先检查channel的key是否已经存在于selected-key set中,如果不存在,则将其加入到selected-key set中去,同时修改key的ready-operation set来表明当前ready的操作,而以前存在于ready-operation set中的信息会被删除。如果对应的key已经存在于selected-key set中,这直接修改其ready-operation set来表明当前ready的操作,删除原来ready-operation set中的信息。
3、如果在第二步中有加入到canceled-key set中的key,在这一步会执行第一步的操作。
selector自身是线程安全的,而他的key set却不是。在一次选择发生的过程中,对于key的关心事件的修改要等到下一次select的时候才会生效。另外,key和其代表的channel有可能在任何时候被cancel和close。因此存在于key set中的key并不代表其key是有效的,也不代表其channel是open的。如果key有可能被其他的线程取消或关闭channel,程序必须小心的同步检查这些条件。
阻塞了的select可以通过调用selector的wakeup方法来唤醒。