Nio框架需要注意的两个问题(1)

研究了一段时间Nio框架,有Netty和Tomcat的Nio Connector总结了一些共性的问题的解决方案。

 

  1. Selector的register和select有锁冲突,例如tomcat的Nio Connector,他采用的Acceptor和Poller的模式,Acceptor只负责接收socket,Poller是负责读写的IO线程,这种模式不用于nginx,Poller(worker)既负责接收和读写的抢占式模块。这样Acceptor和Poller存在的一个交互就是register,Acceptor需要把接收到的socket注册给Poller。Poller实现了Selector执行select和并且遍历selectionKey操作的封装。

 


    假设Poller正在执行Selector的select方法并且同时Acceptor又接收了新的socket并执行register操作,这时候就会发生锁等待,集体参看http://xiaoz5919.iteye.com/blog/1518473。该如何解决这个问题呢。

    Tomcat是这样解决的,把注册当成一个event,当有注册发生时添加一个注册事件到队列中,Poller在每次执行select之前先处理注册事件队列。这样保证了register和select的执行顺序是永远是一致的,先执行register再执行select,有效地避免了锁冲突。

 


 

  再来看看代码,

 

 

   boolean hasEvents = events();//处理register和cancel事件


                    // Time to terminate?

                    if (close) {

                        timeout(0, false);

                        break;

                    }

                    try {

                        if ( !close ) {

                            if (wakeupCounter.getAndSet(-1) > 0) {

                                //if we are here, means we have other stuff to do

                                //do a non blocking select

                                keyCount = selector.selectNow();

                            } else {

                                keyCount = selector.select(selectorTimeout);

                            }

                            wakeupCounter.set(0);

                        }

再看一个细节问题,selector的wakeup是一个很昂贵的工作,假如有多个socket来register也只需一次wakeup,所以tomcat设置了wakeupCounter变量来操作唤醒次数并且只有wakeup==0时才执行一次唤醒操作。

猜你喜欢

转载自xiaoz5919.iteye.com/blog/1735313