直接上源码,注释分析:
package com.play.english.tomcat.thread;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
* @author chaiqx on 2020/5/25
*/
public class LimitLatch {
private final Sync sync;//线程同步器
private final AtomicLong count;//当前连接数目
private volatile long limit;//最大限制连接数
private volatile boolean released;//是否线程全部释放
/**
* 继承的AQS
* AQS其实就是一个框架,具体需要我们去控制线程的阻塞和唤醒
*/
private class Sync extends AbstractQueuedSynchronizer {
public Sync() {
}
/**
* 主要是判断是否达到最大限制数
* <p>
* 如果超过最大限制数的话返回-1 否则返回1
* <p>
* 其实最后主要用来AQS的线程是否阻塞判断
*
* @param args
* @return
*/
@Override
protected int tryAcquireShared(int args) {
long newCount = count.incrementAndGet(); //加入一个连接之后的连接数目
if (!released && newCount > limit) {//不是所有线程唤醒并且已经大于最大限制数
count.decrementAndGet();//把自己的该1个连接数目去掉
return -1;//返回-1表示该线程将要进入阻塞
} else {
return 1;//返回1表示该线程直接通过不用阻塞
}
}
/**
* 主要是释放连接数
*
* @param args
* @return
*/
@Override
protected boolean tryReleaseShared(int args) {
count.decrementAndGet();//释放1个连接
return true;
}
}
/**
* 构造函数
* <p>
* 初始化私有变量
*
* @param limit
*/
public LimitLatch(long limit) {
this.limit = limit;
this.count = new AtomicLong(0);
this.sync = new Sync();
}
/**
* 调用这个用来进行线程的阻塞
* <p>
* 如果当前连接数已经满了,则线程进行循环阻塞
*
* @throws InterruptedException
*/
public void countUpOrAwait() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* 释放一个连接
* <p>
* 唤醒一个线程
*
* @return
*/
public long countDown() {
sync.releaseShared(0);
return getCount();
}
/**
* 唤醒所有的线程
* <p>
* 释放一个连接
*
* @return
*/
public boolean releaseAll() {
released = true;
return sync.releaseShared(0);
}
/**
* 重置连接限制器
*/
public void reset() {
this.count.set(0);
released = false;
}
/**
* 获取当前连接数目
*
* @return
*/
public long getCount() {
return count.get();
}
}