信号
java.util.concurrent.Semaphore
类是一个计数信号量。这意味着它有两种主要方法:
- acquire() 获得信号
- release() 释放信号
计数信号量以给定数量的"许可证"初始化。对于每次对" acquire()"的调用,调用线程都会获得许可。对于每次对release()的调用,都会向信号量返回一个许可。因此,最多N个线程可以通过acquire()
方法而无需任何release()
调用,其中N是初始化信号量的许可数量。许可证只是一个简单的计数器。这里没什么好看的。
信号量用法
信号量通常有两个用途:
- 防止关键部分一次超过N个线程进入。
- 在两个线程之间发送信号。
守卫关键部分
如果使用信号灯来保护关键部分,则尝试进入关键部分的线程通常会首先尝试获取许可,进入关键部分,然后在此之后再次释放许可。像这样:
Semaphore semaphore = new Semaphore(1); //critical section semaphore.acquire(); ... semaphore.release();
在线程之间发送信号
如果使用信号量在线程之间发送信号,则通常一个线程调用" acquire()"方法,另一个线程调用" release()"方法。
如果没有可用的许可,则" acquire()"调用将阻塞,直到另一个线程释放许可为止。类似地,如果没有更多的许可可以释放到该信号量中,则将阻止" release()"调用。
因此可以协调螺纹。例如,如果在线程1将对象插入共享列表后调用了acquire,而线程2在从该列表中获取对象之前调用了" release()",则实际上已经创建了阻塞队列。信号灯中可用的许可数量将对应于阻塞队列可以容纳的最大元素数量。
公平
无法保证从"信号量"获得许可的线程的公平性。也就是说,不能保证调用acquire()
的第一个线程也是获得许可的第一个线程。如果第一个线程在等待许可时被阻塞,那么检查许可的第二个线程就可以在许可被释放时实际在线程1之前获得许可。
如果要强制执行公平性,则" Semaphore"类具有一个构造函数,该构造函数接受一个布尔值来告知该信号是否应强制执行公平性。强制公平会影响性能/并发性,因此除非需要,请不要启用它。
以下是在公平模式下创建Semaphore
的方法:
Semaphore semaphore = new Semaphore(1, true);
更多方法
java.util.concurrent.Semaphore
类还有很多方法。例如:
availablePermits()
acquireUninterruptible()
drainPermits()
hasQueuedThreads()
getQueuedThreads()
tryAcquire()
请查看JavaDoc,以获取有关这些方法的更多详细信息。