Semaphore(/ˈseməfɔːr/)介绍
Semaphore,俗称信号量,它是操作系统中PV操作的原语在java的实现,它也是基于AbstractQueuedSynchronizer实现的。
Semaphore的功能非常强大,大小为1的信号量就类似于互斥锁,通过同时只能有一个线程获取信号量实现。大小为n(n>0)的信号量可以实现限流的功能,它可以实现只能有n个线程同时获取信号量
PV操作
PV操作是操作系统一种实现进程互斥与同步的有效方法。 PV操作与信号量(S)的处理相关,P表示通过的意思,V表示释放的意思。用PV操作来管理共享资源时,首先要确保PV操作自身执行的正确性。
P操作的主要动作是:
①S减1;
②若S减1后仍大于或等于0,则进程继续执行;
③若S减1后小于0,则该进程被阻塞后放入等待该信号量的等待队列中,然后转进程调度。
V操作的主要动作是:
①S加1;
②若相加后结果大于0,则进程继续执行;
③若相加后结果小于或等于0,则从该信号的等待队列中释放一个等待进程,然后再返回原进程继续执行或转进程调度。
Semaphore 常用方法
构造器
- permits 表示许可证的数量(资源数)
- fair 表示公平性,如果这个设为 true 的话,下次执行的线程会是等待最久的线程
常用方法
public void acquire() throws InterruptedException public boolean tryAcquire() public void release() public int availablePermits() public final int getQueueLength() public final boolean hasQueuedThreads() protected void reducePermits(int reduction) protected Collection<Thread> getQueuedThreads()
- acquire() 表示阻塞并获取许可
- tryAcquire() 方法在没有许可的情况下会立即返回 false,要获取许可的线程不会阻塞
- release() 表示释放许可
- int availablePermits():返回此信号量中当前可用的许可证数。
- int getQueueLength():返回正在等待获取许可证的线程数。
- boolean hasQueuedThreads():是否有线程正在等待获取许可证。
- void reducePermit(int reduction):减少 reduction 个许可证
- Collection getQueuedThreads():返回所有等待获取许可证的线程集合
应用场景
可以用于做流量控制,确保同一时间最多只有指定数量的线程在工作,特别是公用资源有限的应用场景
限流
// 声明3个窗口 state: 资源数 Semaphore windows = new Semaphore(3); for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { // 占用窗口 加锁 windows.acquire(); System.out.println(Thread.currentThread().getName() + ": 开始买票"); //模拟买票流程 Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + ": 购票成功"); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 释放窗口 windows.release(); } } }).start(); }
Semaphore 原理
创建Semaphore对象将state设置为指定值。调用acquire方法使用CAS将state减掉指定值,同时判断减掉后的值是否大于0,如果小于0,则将当前线程挂起并加入阻塞队列。调用release方法将state加上指定值,未成功前一直死循环,直到成功,然后唤醒等待队列中的线程。