创建完接收器IoAcceptor之后,紧接着就是启动服务端的监听,准备接受客户端的请求。启动监听的入口是IoAcceptor接口的bind方法,方法的实现在AbstractIoAcceptor类中,具体的逻辑处理是AbstractPollingIoAcceptor类的bindInternal方法。我们重点看下bindInternal方法中调用startupAcceptor方法启动接收线程的过程。
private void startupAcceptor() throws InterruptedException {
// If the acceptor is not ready, clear the queues
// TODO : they should already be clean : do we have to do that ?
if (!selectable) {
registerQueue.clear();
cancelQueue.clear();
}
// start the acceptor if not already started
Acceptor acceptor = acceptorRef.get();
if (acceptor == null) {
lock.acquire();
acceptor = new Acceptor();
if (acceptorRef.compareAndSet(null, acceptor)) {
executeWorker(acceptor);
} else {
lock.release();
}
}
}
其中selectable的值在创建IoAcceptor的时候被置为true,那么清空两个队列的操作便不会执行。接着从AtomicReference对象中获取Acceptor的值,如果获取到的Acceptor值为空的话,则会创建一个Acceptor对象。注意Acceptor是接收请求的线程,而IoAcceptor是一个接口,表示服务端的接收器。创建完Acceptor线程之后通过acceptorRef的compareAndSet方法比较acceptorRef是否为空,如果是的话acceptorRef的值会被更新为刚创建的Acceptor线程的值,由于compareAndSet的操作线程安全的,因此比较,更新这两步操作是原子性的。设置完acceptorRef的值便会将Acceptor线程添加到接收线程池中,并且启动Acceptor线程。Acceptor线程主要功能实现代码如下:
while (selectable) {
try {
// Detect if we have some keys ready to be processed
// The select() will be woke up if some new connection
// have occurred, or if the selector has been explicitly
// woke up
int selected = select();
// this actually sets the selector to OP_ACCEPT,
// and binds to the port on which this class will
// listen on
nHandles += registerHandles();
// Now, if the number of registred handles is 0, we can
// quit the loop: we don't have any socket listening
// for incoming connection.
if (nHandles == 0) {
acceptorRef.set(null);
if (registerQueue.isEmpty() && cancelQueue.isEmpty()) {
assert (acceptorRef.get() != this);
break;
}
if (!acceptorRef.compareAndSet(null, this)) {
assert (acceptorRef.get() != this);
break;
}
assert (acceptorRef.get() == this);
}
if (selected > 0) {
// We have some connection request, let's process
// them here.
processHandles(selectedHandles());
}
// check to see if any cancellation request has been made.
nHandles -= unregisterHandles();
}
其中select方法是一个阻塞模式的方法,返回准备就绪的键的数目,仅在至少选择一个通道、调用此选择器的 wakeup 方法,或者当前的线程已中断(以先到者为准)后此方法才返回。registerHandles和unregisterHandles从字面上来看就是两个功能相对的方法,registerHandles方法中封装了基本的NIO操作,比如打开通道,绑定监听端口,将ServerSocketChannel注册到选择器Selector上,监听Accept事件等。而unregisterHandles则是取消通道注册在选择器Selector上的Accept事件,关闭通道等。当select方法返回的值大于0时,也就是产生了Accept事件,说明收到了客户端的连接请求,这时将会调用processHandles方法启动I/O处理线程IoProcessor处理请求。
关于IoProcessor的部分下回继续分解。。。。。。