Semaphore
限流操作,限制某个资源同时被访问的次数,基于共享锁实现。 本质上: 抢占一个令牌. -> 如果抢占到令牌,就通行, 否则,就阻塞!
使用场景
- 停车场
- …
特点
- semaphore 也就是我们常说的信号灯,semaphore 可以控制同时访问的线程个数,通过 acquire 获取一个许可,如果没有就等待,通过 release 释放一个许可。
- …
code
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@Slf4j
public class SemaphoreDemo {
// 20个用户同时访问
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
// 信号量:限流,同一时刻只允许有permits个线程(用户)同时访问
int permits = 2;
final Semaphore semaphore = new Semaphore(permits);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
// acquire(semaphore, threadNum);
// acquireMore(semaphore, threadNum);
tryAcquire(semaphore, threadNum);
// tryAcquireWithTime(semaphore, threadNum);
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
/**
* 获取一个许可
*
* @param semaphore
* @param threadNum
* @throws Exception
*/
private static void acquire(Semaphore semaphore, int threadNum) throws Exception {
// 获取一个许可
semaphore.acquire();
log.info("{}", threadNum);
Thread.sleep(1000);
// 释放一个许可
semaphore.release();
}
/**
* 获取多个个许可
*
* @param semaphore
* @param threadNum
* @throws Exception
*/
private static void acquireMore(Semaphore semaphore, int threadNum) throws Exception {
// 获取多个个许可
semaphore.acquire(2);
log.info("{}", threadNum);
Thread.sleep(1000);
// 释放多个许可
semaphore.release(2);
}
/**
* 尝试获取一个许可,获取不到则跳过当前包裹的代码
*
* @param semaphore
* @param threadNum
* @throws Exception
*/
private static void tryAcquire(Semaphore semaphore, int threadNum) throws Exception {
// 尝试获取一个许可
if (semaphore.tryAcquire()) {
log.info("{}", threadNum);
Thread.sleep(1000);
// 释放一个许可
semaphore.release();
} else {
// 获取不到许可
log.info("获取不到许可:{}", threadNum);
}
}
/**
* 尝试获取一个许可(带超时时间),给定时间内获取不到则跳过当前包裹的代码
*
* @param semaphore
* @param threadNum
* @throws Exception
*/
private static void tryAcquireWithTime(Semaphore semaphore, int threadNum) throws Exception {
// 尝试获取一个许可(带超时时间)
if (semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS)) { // 尝试获取一个许可
log.info("{}", threadNum);
Thread.sleep(1000);
// 释放一个许可
semaphore.release();
} else {
// 获取不到许可
log.info("获取不到许可:{}", threadNum);
}
}
}