Semaphore
Semaphore俗称信用量,是JUC包下一个并发工具类,其实基于AQS实现的共享锁模式,包含非公平锁和公平锁实现,主要用用于控制多线程的并发访问次数,可做高并发下限流。
java模拟Smaphore限流:
public class SemaphoreDemo {
//定义线程池
private static ExecutorService executorService = Executors.newCachedThreadPool();
public static void main(String[] args) {
//定义一个信号量,限制3个同时执行线程
Semaphore semaphore = new Semaphore(3);
//模拟多线程
for (int i = 0; i < 10; i++) {
executorService.submit(() -> {
try {
//尝试获取信号量
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+":开始执行");
//模拟负责业务操作-休眠2秒
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+":执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放信号量
semaphore.release();
System.out.println(Thread.currentThread().getName()+":----------释放");
}
});
}
}
}
控制台输出如下:
pool-1-thread-1:开始执行 (同时执行)
pool-1-thread-2:开始执行 (同时执行)
pool-1-thread-3:开始执行 (同时执行)
pool-1-thread-2:执行完成
pool-1-thread-2:----------释放
pool-1-thread-3:执行完成
pool-1-thread-3:----------释放
pool-1-thread-4:开始执行
pool-1-thread-5:开始执行
pool-1-thread-1:执行完成
pool-1-thread-6:开始执行
pool-1-thread-1:----------释放
pool-1-thread-4:执行完成
pool-1-thread-6:执行完成
pool-1-thread-5:执行完成
pool-1-thread-8:开始执行
pool-1-thread-6:----------释放
pool-1-thread-4:----------释放
pool-1-thread-7:开始执行
pool-1-thread-9:开始执行
pool-1-thread-5:----------释放
pool-1-thread-8:执行完成
pool-1-thread-8:----------释放
pool-1-thread-10:开始执行
pool-1-thread-9:执行完成
pool-1-thread-7:执行完成
pool-1-thread-9:----------释放
pool-1-thread-7:----------释放
pool-1-thread-10:执行完成
pool-1-thread-10:----------释放
Semaphore底层解析:
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
默认非公平锁实现:
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
CAS自旋获取锁
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
//这个就是我们传参进来的限制数量3
int available = getState();
//当获取一次锁后state会累加1,释放一次锁则减1
//判断剩余数量>0表示获取成功,否则自旋等待
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}