接着上面的流程,现在请求到了Poller的#register()方法。
public
void
register(
final
NioChannel socket)
{
socket.setPoller( this );
// KeyAttachment是对NioChannel信息的包装,同样是非GC
KeyAttachment key = keyCache.poll();
final KeyAttachment ka = key != null ? key : new KeyAttachment(socket);
ka.reset( this , socket, getSocketProperties().getSoTimeout());
ka.setKeepAliveLeft(NioEndpoint. this .getMaxKeepAliveRequests());
// PollerEvent的初始化,非GC Again
PollerEvent r = eventCache.poll();
// this is what OP_REGISTER turns into.
// 读取数据的事件
ka.interestOps(SelectionKey.OP_READ);
if (r == null )
r = new PollerEvent(socket, ka, OP_REGISTER);
else
r.reset(socket, ka, OP_REGISTER);
// 把事件加到Poller
addEvent(r);
}
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
public
void
addEvent(Runnable event)
{
// 把事件加入到队列中
events.offer(event);
// ++wakeupCounter
if (wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
}
其实也挺好懂的,就是把NioChannel作为OP_REGISTER事件注册到Poller,这样在Poller的#run()方法中就可以对加入Poller的事件进行处理了。
public
void
run()
{
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
while (running) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
while (paused && ( ! close)) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
Thread.sleep( 100 );
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (InterruptedException e) {
// Ignore
}
}
boolean hasEvents = false ;
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
hasEvents = (hasEvents | events());
// Time to terminate?
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (close) {
timeout( 0 , false );
break ;
}
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if ( ! close) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (wakeupCounter.get() > 0 ) {
// 立刻返回 I/O 就绪的那些通道的键
keyCount = selector.selectNow();
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} else {
keyCount = selector.keys().size();
// 这里把wakeupCounter设成-1,在addEvent的时候就会唤醒selector
wakeupCounter.set( - 1 );
// 使用阻塞的方式
keyCount = selector.select(selectorTimeout);
}
wakeupCounter.set( 0 );
}
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (close) {
timeout( 0 , false );
selector.close();
break ;
}
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (NullPointerException x) {
// sun bug 5076772 on windows JDK 1.5
if (log.isDebugEnabled())
log.debug( " Possibly encountered sun bug 5076772 on windows JDK 1.5 " , x);
if (wakeupCounter == null || selector == null )
throw x;
continue ;
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (CancelledKeyException x) {
// sun bug 5076772 on windows JDK 1.5
if (log.isDebugEnabled())
log.debug( " Possibly encountered sun bug 5076772 on windows JDK 1.5 " , x);
if (wakeupCounter == null || selector == null )
throw x;
continue ;
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (Throwable x) {
ExceptionUtils.handleThrowable(x);
log.error( "" , x);
continue ;
}
// either we timed out or we woke up, process events first
if (keyCount == 0 )
hasEvents = (hasEvents | events());
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
Iterator < SelectionKey > iterator = keyCount > 0 ? selector.selectedKeys().iterator()
: null ;
// Walk through the collection of ready keys and dispatch
// any active event.
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
while (iterator != null && iterator.hasNext()) {
SelectionKey sk = iterator.next();
// 这里的KeyAttachment实在#register()方法中注册的
KeyAttachment attachment = (KeyAttachment) sk.attachment();
attachment.access();
iterator.remove();
// 继续流程
processKey(sk, attachment);
} // while
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
// process timeouts
timeout(keyCount, hasEvents);
if (oomParachute > 0 && oomParachuteData == null )
checkParachute();
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (OutOfMemoryError oom) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
oomParachuteData = null ;
releaseCaches();
log.error( "" , oom);
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (Throwable oomt) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
System.err.println(oomParachuteMsg);
oomt.printStackTrace();
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (Throwable letsHopeWeDontGetHere) {
ExceptionUtils.handleThrowable(letsHopeWeDontGetHere);
}
}
}
} // while
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
synchronized ( this ) {
this .notifyAll();
}
stopLatch.countDown();
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
}
这个方法有2个方法需要关注一下:#events()和#processKey():
public
boolean
events()
{
boolean result = false ;
// synchronized (events) {
Runnable r = null ;
// 返回是事件队列中是否有事件
result = (events.size() > 0 );
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
while ((r = events.poll()) != null ) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
// 执行KeyEvent的#run()
r.run();
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (r instanceof PollerEvent) {
((PollerEvent) r).reset();
// 对KeyEvent进行回收
eventCache.offer((PollerEvent) r);
}
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (Throwable x) {
log.error( "" , x);
}
}
// events.clear();
// }
return result;
}
这里执行了SocketChannel对应的KeyEvent的#run()方法,在这个方法里给SocketChannel注册了OP_READ:
public
void
run()
{
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (interestOps == OP_REGISTER) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
// 给SocketChannel注册OP_READ
socket.getIOChannel().register(socket.getPoller().getSelector(), SelectionKey.OP_READ,
key);
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} catch (Exception x) {
log.error( "" , x);
}
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} else {
// 这里应该是对comet进行支持的,暂时先不看
......
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
} // end if
}
//
run
第二个是#processKey()方法,里边的很多流程我现在不是很关心,都略去了,
protected
boolean
processKey(SelectionKey sk, KeyAttachment attachment)
{
boolean result = true ;
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
try {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (close) {
cancelledKey(sk, SocketStatus.STOP, false );
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} else if (sk.isValid() && attachment != null ) {
attachment.access(); // make sure we don't time out valid sockets
sk.attach(attachment); // cant remember why this is here
NioChannel channel = attachment.getChannel();
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (sk.isReadable() || sk.isWritable()) {
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (attachment.getSendfileData() != null ) {
processSendfile(sk, attachment, true , false );
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} else if (attachment.getComet()) { // 这里应该是对comet的支持
......
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
} else {
// 这个分支是现在比较关心的
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
if (isWorkerAvailable()) { // 这个好像还没实现
// 这个#unreg()很巧妙,防止了通道对同一个事件不断select的问题
unreg(sk, attachment, sk.readyOps());
boolean close = ( ! processSocket(channel, null , true ));
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)