Selector默认是WindowsSelectorImpl的一个实例,
当调用了SelectorImpl的select()方法的时候,调用selector(timeout),之后会调用lockAndDoSelect(),在这个方法中,主要调用了doSelect()方法,参数与传进来的一致,以WindowsSelectorImpl为例子,实现的doSelect()方法。
protected int doSelect(long var1) throws IOException {
if(this.channelArray == null) {
throw new ClosedSelectorException();
} else {
this.timeout = var1;
this.processDeregisterQueue();
if(this.interruptTriggered) {
this.resetWakeupSocket();
return 0;
} else {
this.adjustThreadsCount();
this.finishLock.reset();
this.startLock.startThreads();
try {
this.begin();
try {
this.subSelector.poll();
} catch (IOException var7) {
this.finishLock.setException(var7);
}
if(this.threads.size() > 0) {
this.finishLock.waitForHelperThreads();
}
} finally {
this.end();
}
this.finishLock.checkForException();
this.processDeregisterQueue();
int var3 = this.updateSelectedKeys();
this.resetWakeupSocket();
return var3;
}
}
}
首先调用processD额registerQueue()方法,从而将已经准备注销注册的channel进行注销注册。
void processDeregisterQueue() throws IOException {
Set var1 = this.cancelledKeys();
synchronized(var1) {
if(!var1.isEmpty()) {
Iterator var3 = var1.iterator();
while(var3.hasNext()) {
SelectionKeyImpl var4 = (SelectionKeyImpl)var3.next();
try {
this.implDereg(var4);
} catch (SocketException var11) {
throw new IOException("Error deregistering key", var11);
} finally {
var3.remove();
}
}
}
}
}
遍历取得所有要注销注册的SelectionKey(加到cancelledKeys中的SelectionKey),并且依次调用implDereg()进行注销绑定。
protected void implDereg(SelectionKeyImpl var1) throws IOException {
int var2 = var1.getIndex();
assert var2 >= 0;
Object var3 = this.closeLock;
synchronized(this.closeLock) {
if(var2 != this.totalChannels - 1) {
SelectionKeyImpl var4 = this.channelArray[this.totalChannels - 1];
this.channelArray[var2] = var4;
var4.setIndex(var2);
this.pollWrapper.replaceEntry(this.pollWrapper, this.totalChannels - 1, this.pollWrapper, var2);
}
var1.setIndex(-1);
}
this.channelArray[this.totalChannels - 1] = null;
--this.totalChannels;
if(this.totalChannels != 1 && this.totalChannels % 1024 == 1) {
--this.totalChannels;
--this.threadsCount;
}
this.fdMap.remove(var1);
this.keys.remove(var1);
this.selectedKeys.remove(var1);
this.deregister(var1);
SelectableChannel var7 = var1.channel();
if(!var7.isOpen() && !var7.isRegistered()) {
((SelChImpl)var7).kill();
}
}
这里如果需要注销操作的channel已经是selector中最后一个了,那么直接从数组中移除。
否则,则需要将当前需要移除的channel与数组最后一个channel进行位置交换,保证数组中间位置连续,再移除。
之后操作即就是对注册操作的反向操作。
完成真正注销后,调用adjustThreadCount()来调整线程的数量:
private void adjustThreadsCount() {
int var1;
if(this.threadsCount > this.threads.size()) {
for(var1 = this.threads.size(); var1 < this.threadsCount; ++var1) {
WindowsSelectorImpl.SelectThread var2 = new WindowsSelectorImpl.SelectThread(var1);
this.threads.add(var2);
var2.setDaemon(true);
var2.start();
}
} else if(this.threadsCount < this.threads.size()) {
for(var1 = this.threads.size() - 1; var1 >= this.threadsCount; --var1) {
((WindowsSelectorImpl.SelectThread)this.threads.remove(var1)).makeZombie();
}
}
}
在Selector中,每1024条channel就需要重新打开一个线程加入进行监听的操作,这里,重新根据当前应该有的线程数量与此时现存的线程数量进行比较,进行动态调整。
在此之后,调用begin()方法,准备开始正式进行select操作。
protected final void begin() {
if (interruptor == null) {
interruptor = new Interruptible() {
public void interrupt(Thread ignore) {
AbstractSelector.this.wakeup();
}};
}
AbstractInterruptibleChannel.blockedOn(interruptor);
Thread me = Thread.currentThread();
if (me.isInterrupted())
interruptor.interrupt(me);
}
begin()方法判断这里interruptor是否为空,如果为空,则会在这里重新生成一个。
这里的Interruptor保证了当线程阻塞在io操作上,并且被interruptor时,保证selector能够被唤醒。
在begin()方法执行完毕后,将会调用其subSelector的poll()方法,正式开始select操作。
private int poll() throws IOException {
return this.poll0(WindowsSelectorImpl.this.pollWrapper.pollArrayAddress, Math.min(WindowsSelectorImpl.this.totalChannels, 1024), this.readFds, this.writeFds, this.exceptFds, WindowsSelectorImpl.this.timeout);
}
private int poll(int var1) throws IOException {
return this.poll0(WindowsSelectorImpl.this.pollWrapper.pollArrayAddress + (long)(this.pollArrayIndex * PollArrayWrapper.SIZE_POLLFD), Math.min(1024, WindowsSelectorImpl.this.totalChannels - (var1 + 1) * 1024), this.readFds, this.writeFds, this.exceptFds, WindowsSelectorImpl.this.timeout);
}
private native int poll0(long var1, int var3, int[] var4, int[] var5, int[] var6, long var7);
这里poll0()是native方法(原生方法的实现),主要为了监听pollWrapper中保存的fd是否有数据进出,如果没有进出,那么此处在timeout时间里一直保持阻塞状态。
数据监听完成后取得相应数据,在此之后将重新检验一边已经取消注册的channel,进行注销。之后调用updateSelectedKeys()方法。
private int updateSelectedKeys() {
++this.updateCount;
byte var1 = 0;
int var4 = var1 + this.subSelector.processSelectedKeys(this.updateCount);
WindowsSelectorImpl.SelectThread var3;
for(Iterator var2 = this.threads.iterator(); var2.hasNext();
var4 += var3.subSelector.processSelectedKeys(this.updateCount)) {
var3 = (WindowsSelectorImpl.SelectThread)var2.next();
}
return var4;
}
这里对所有的线程调用processSelectedKeys来处理所有线程在poll过程中取得的结果进行处理,然后返回所以线程中处理的channel数量的总和。
接下来看processSelectedKeys()方法:
private int processSelectedKeys(long var1) {
byte var3 = 0;
int var4 = var3 + this.processFDSet(var1, this.readFds, 1, false);
var4 += this.processFDSet(var1, this.writeFds, 6, false);
var4 += this.processFDSet(var1, this.exceptFds, 7, true);
return var4;
}
private int processFDSet(long var1, int[] var3, int var4, boolean var5) {
int var6 = 0;
for(int var7 = 1; var7 <= var3[0]; ++var7) {
int var8 = var3[var7];
if(var8 == WindowsSelectorImpl.this.wakeupSourceFd) {
synchronized(WindowsSelectorImpl.this.interruptLock) {
WindowsSelectorImpl.this.interruptTriggered = true;
}
} else {
WindowsSelectorImpl.MapEntry var9 = WindowsSelectorImpl.this.fdMap.get(var8);
if(var9 != null) {
SelectionKeyImpl var10 = var9.ski;
if(!var5 || !(var10.channel() instanceof SocketChannelImpl) || !WindowsSelectorImpl.this.discardUrgentData(var8)) {
if(WindowsSelectorImpl.this.selectedKeys.contains(var10)) {
if(var9.clearedCount != var1) {
if(var10.channel.translateAndSetReadyOps(var4, var10) && var9.updateCount != var1) {
var9.updateCount = var1;
++var6;
}
} else if(var10.channel.translateAndUpdateReadyOps(var4, var10) && var9.updateCount != var1) {
var9.updateCount = var1;
++var6;
}
var9.clearedCount = var1;
} else {
if(var9.clearedCount != var1) {
var10.channel.translateAndSetReadyOps(var4, var10);
if((var10.nioReadyOps() & var10.nioInterestOps()) != 0) {
WindowsSelectorImpl.this.selectedKeys.add(var10);
var9.updateCount = var1;
++var6;
}
} else {
var10.channel.translateAndUpdateReadyOps(var4, var10);
if((var10.nioReadyOps() & var10.nioInterestOps()) != 0) {
WindowsSelectorImpl.this.selectedKeys.add(var10);
var9.updateCount = var1;
++var6;
}
}
var9.clearedCount = var1;
}
}
}
}
}
return var6;
}
这里主要对之前监听到的发生io事件需要处理的fd与对应的channel进行操作,根据读取到的fd取得selector下注册了的相应的channel,根据监听到其所发生事件类型(读、写、异常),从而更新channel应该的状态。
在此操作之后,相应的selector的select也相应完成。