Tomcat源码阅读之闭锁的实现与连接数量的控制(三)

2014-11-24 11:18:58 · 作者: · 浏览: 2
g.error("", oom); }catch ( Throwable oomt ) { try { try { System.err.println(oomParachuteMsg); oomt.printStackTrace(); }catch (Throwable letsHopeWeDontGetHere){ ExceptionUtils.handleThrowable(letsHopeWeDontGetHere); } }catch (Throwable letsHopeWeDontGetHere){ ExceptionUtils.handleThrowable(letsHopeWeDontGetHere); } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("endpoint.accept.fail"), t); } } state = AcceptorState.ENDED; //设置acceptor的状态为ended }

这里读一下Accecptor,的run方法可以知道,每次在调用serverSocketChannel的accept方法之前都会调用countUpOrAwaitConnection方法来增加闭锁的计数,如果有问题,那就会调用countDownConnection方法来降低闭锁的计数。。。

其实这里通过这两个方法就知道他们是干嘛的了,先来看看countUpOrAwaitConnection吧:

    //这里用于增加闭锁的计数
    protected void countUpOrAwaitConnection() throws InterruptedException {
        if (maxConnections==-1) return;
        LimitLatch latch = connectionLimitLatch;
        if (latch!=null) latch.countUpOrAwait();  //增加闭锁的counter
    }

没啥意思吧,就是调用刚刚创建的闭锁的countUpOrAwait方法,接下来来看看countDownConnection方法吧:

    //用于减少闭锁的计数
    protected long countDownConnection() {
        if (maxConnections==-1) return -1;
        LimitLatch latch = connectionLimitLatch;
        if (latch!=null) {
            long result = latch.countDown();
            if (result<0) {
                getLog().warn("Incorrect connection count, multiple socket.close called on the same socket." );
            }
            return result;
        } else return -1;
    }

这个也没啥意思吧。。。就是调用闭锁的countDown方法。。。

嗯,到这里整个Tomcat如何控制连接的数量就算是比较清楚了吧。。。

最后,我们知道是通过调用endpoint的cancelledKey方法来关闭一个连接的,来看看它的实现吧:

     //取消一个注册
        public void cancelledKey(SelectionKey key, SocketStatus status) {
            try {
                if ( key == null ) return;//nothing to do
                KeyAttachment ka = (KeyAttachment) key.attachment();
                if (ka != null && ka.isComet() && status != null) {
                    ka.setComet(false);//to avoid a loop
                    if (status == SocketStatus.TIMEOUT ) {
                        if (processSocket(ka.getChannel(), status, true)) {
                            return; // don't close on comet timeout
                        }
                    } else {
                        // Don't dispatch if the lines below are canceling the key
                        processSocket(ka.getChannel(), status, false);
                    }
                }
                key.attach(null);  //将附件设置为null
                if (ka!=null) handler.release(ka);  //可以取消这个attachment了
                else handler.release((SocketChannel)key.channel());
                if (key.isValid()) key.cancel();  //取消key
                if (key.channel().isOpen()) {  //如果channel还是打开的,那么需要关闭channel
                    try {
                        key.channel().close();
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString(
                                    "endpoint.debug.channelCloseFail"), e);
                        }
                    }
                }
                try {
                    if (ka!=null) {
                        ka.getSocket().close(true); //关闭sockt
                    }
                } catch (Exception e){
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString(
                                "endpoint.debug.socketCloseFail"), e);
                    }
                }
                try {
                    if (ka != null && ka.getSendfileData() != null
                            && ka.getSendfileData().fchannel != null
                            && ka.getSendfileData().fchannel.isOpen()) {
                        ka.getSendfileData().fchannel.close();
                    }
                } catch (Exception ignore) {
                }
                if (ka!=null) {
                    ka.reset();
                    countDownConnection();  //降低用于维护连接数量的闭锁
                }
            } catch (Throwable e) {
                ExceptionUtils.handleThrowable(e);
                if (log.isDebugEnabled()) log.error("",e);
            }
        }

这里可以看到调用了countDownConnection方法来降低闭锁的计数。。


最后总结:Tomcat通过在acceptor中对闭锁的获取来控制总连接的数量,如果连接数量达到了最大的限制,那么将会被阻塞。。直到有连接关闭为止。。。这样acceptor的线程就又被唤醒了。。。