定义
Semaphore :信号量,并发控制中用于控制某个资源同时被访问的个数。例如程序中某个方法执行耗时长,所需资源量大。可以通过Semaphore控制同一时刻访问该方法的线程数。
应用场景
主要用于流量控制,特别是公共资源有限
的的应用场景(数据库连接)或者一些慢服务
。
主要方法
- public Semaphore(int permits) :构造函数一,permits为信号量许可证的大小;
- public Semaphore(int permits, boolean fair) :构造函数二:fair为是否设置公平策略参数,如果为true,申请许可证的等待线程会进入FIFO队列中。若为false,允许等待的线程有插队的可能。
- public void acquire():以阻塞的方式获取一个申请许可证,在有可用的许可证时候就返回许可;如果没有可用的许可则阻塞等待,直至获取到许可;
- public void acquire(int permits):同时获取permits个许可;
- public void release():释放一个许可;
- public void acquire(int permits):释放permits个许可;
- public boolean tryAcquire():尝试获取许可证,如果当前没有可用的许可证,申请的线程不需要进入阻塞,而是继续往下执行;
- public boolean tryAcquire(long timeout, TimeUnit unit) :带有超时时间去获取蓄许可证。例如“5秒钟内还是获取不到许可证,我就继续往下执行,干自己的事!”
- public int availablePermits():查询可用的许可;
例子
package com.mark.learning.concurrent2.flowcontrol.semaphore;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @Description: 演示Semaphore用法
* @Author: Mark
* @CreateDate: 2020/2/3 14:15
* @Version: 1.0
* @Copyright : 豆浆油条个人非正式工作室
*/
@Slf4j
class Task implements Runnable{
private static final Semaphore SEMAPHORE = new Semaphore(3,true);
@Override
public void run() {
//获取信号量许可证
try {
SEMAPHORE.acquire();
log.info(Thread.currentThread().getName()+"获取到了 信号量许可证");
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟 耗时长的程序
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//释放信号量
SEMAPHORE.release();
log.info(Thread.currentThread().getName()+"释放了 信号量许可证");
}
}
public class SemaphoreDemo1 {
private static ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
//运行十个线程
for (int i = 0; i < 10; i++) {
executorService.execute(new Task());
}
executorService.shutdown();
}
}
运行结果
16:39:57.795 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1获取到了 信号量许可证
16:39:57.795 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2获取到了 信号量许可证
16:39:57.795 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5获取到了 信号量许可证
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1释放了 信号量许可证
16:40:02.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3获取到了 信号量许可证
16:40:02.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4获取到了 信号量许可证
16:40:02.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5释放了 信号量许可证
16:40:02.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2释放了 信号量许可证
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1获取到了 信号量许可证
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4释放了 信号量许可证
16:40:07.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1释放了 信号量许可证
16:40:07.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3释放了 信号量许可证
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4获取到了 信号量许可证
16:40:07.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5获取到了 信号量许可证
16:40:07.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2获取到了 信号量许可证
16:40:12.802 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2释放了 信号量许可证
16:40:12.802 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1获取到了 信号量许可证
16:40:12.802 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5释放了 信号量许可证
16:40:12.802 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4释放了 信号量许可证
16:40:17.803 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1释放了 信号量许可证
通过分析log的打印时间,每次最多只能允许3个线程同时执行。
注意点
- 一次获取可获取和释放多个许可证。
semaphore.acquire(3);//一次获取三个许可
semaphore.release(3);//一次释放三个许可
- 获取许可和释放许可的数量需要保持一致;
- 释放许可不一定由获取的许可来完成。例如线程A获取了许可,也可以由线程B来释放许可