Tomcat知多少 -- 01. 使用LimitLatch限制最大连接数

1. 概述

在英文中,latch是“门闩”的意思,这跟锁(lock)所要表达的意思接近,获取到latch则可以进入房间,否则只能等待。而我猜测使用latch而不是用lock可能是想表达“轻量级锁”。

LimitLatch实例在初始化时会设置一个资源的上限值,在某一时刻,资源使用未达到上限则可以获取锁并消耗一个资源,资源使用达到上限后,随后到来的请求将进入队列,直到有资源得到释放。

LimitLatch是一个共享性质的锁,这里的共享概念来自于AQS,指的是不同的线程可以同时获取该锁。

实际上,在JDK的JUC包中,还有一个CountDownLatch存在,两者都是基于AQS框架实现的同步工具类,不过表达的意思却完全不同

CountDownLatch表示的行为是“所有线程都到达了某一状态后才执行动作”,LimitLatch则更像是Semaphore,用于记录资源的使用。

如上图所示,LimitLatch类的结构并不复杂,它有四个私有成员变量,作用如下:

private final Sync sync;                // 同步工具类,Sync是内部类
private final AtomicLong count;         // 当前使用资源数目
private volatile long limit;            // 总的可用资源数目
private volatile boolean released = false;    // 资源是否被全部释放

另外,有两个主要的公有方法:

  • countUpOrAwait()用来获取一个资源,如果当前没有资源可以获取,则进入等待队列;
  • countDown()则用于释放一个资源。

2. LimitLatch在Tomcat中的作用

在Tomcat中,LimitLatch类用于限制Tomcat可接受的连接数量。

2.1 初始化LimitLatch

在NioEndPoint类中,initializeConnectionLatch()用于创建LimitLatch实例。

protected LimitLatch initializeConnectionLatch() {
    if (maxConnections==-1) return null;
    if (connectionLimitLatch==null) {
        //  默认的最大连接数是 8 * 1024
        connectionLimitLatch = new LimitLatch(getMaxConnections());
    }
    return connectionLimitLatch;
}

2.2 在Acceptor中使用LimitLatch限制连接数量

如下面代码所示,当超过最大连接数时,Acceptor线程将通过自旋锁等待。

public class Acceptor<U> implements Runnable {
    @Override
    public void run() {
    	...
        //如果达到了最大连接数则等待
	endpoint.countUpOrAwaitConnection();
	...
	// 从serverSocket中接受一个连接
	socket = endpoint.serverSocketAccept();
	...
    }
}

2.3 当socket被销毁时,占有的锁将被释放

NioEndPoint类的destroySocket()方法中,每当销毁一个socket时就释放一个连接资源。

@Override
protected void destroySocket(SocketChannel socket) {
    countDownConnection();    // 实际上调用了LimitLatch的countDown()方法
    try {
        socket.close();
    } catch (IOException ioe) {
        if (log.isDebugEnabled()) {
            log.debug(sm.getString("endpoint.err.close"), ioe);
        }
    }
}
posted @ 2020-05-10 22:10  SanjiApollo  阅读(864)  评论(0编辑  收藏  举报