我正在阅读Java Concurrency in Practice一书。在关于java.util.concurrent.Semaphore
的部分中,本书中包含以下行。它是关于其“虚拟许可”对象的实现的评论
实现没有实际的许可对象,
Semaphore
也有 没有将分发的许可证与线程相关联,因此获得许可证 一个线程可以从另一个线程释放。你可以想到acquire
占用许可证,release
占用许可证;一个Semaphore
不限于使用它创建的许可数量。
有人可以解释一下吗?我无法理解这一点。如果我们创建一个固定大小的池,我们会创建固定数量的“许可”。从上面的陈述看,“许可证”似乎可以继续增长。为什么这样设计?
答案 0 :(得分:9)
实现只有一个计数器,而不是“分发”许可对象。当“创建”新许可证时,计数器会增加,当“返回”许可证时,计数器会减少。
这比始终创建实际对象的性能要好得多。
权衡是信号量本身无法检测某些类型的编程错误(例如未经授权的许可证现金或信号量泄漏)。作为编码员,你必须确保自己遵守规则。
答案 1 :(得分:6)
有人可以解释一下吗?从上面的陈述看,“许可证”似乎可以继续增长。
信号量是许可证的计数器。获得就像是等待而不是低于零的减量。它没有上限。
为什么这样设计?
因为它很简单。
答案 2 :(得分:4)
如第一篇文章所述" 信号量不仅限于使用创建的许可证数量"
每次调用.release()API都会将许可数增加一。所以Semaphores没有固定的许可证大小
答案 3 :(得分:2)
我认为这意味着我们可能需要Semaphore作为我们发布“额外”的时间以及它创建的许可证的时间。
如:
Semaphore s = new Semaphore(1); // one permit when initialize
s.acquire();
s.release();
s.release(); // "extra" release.
此时,此信号量允许最初一个许可和一个“额外”许可
答案 4 :(得分:0)
我们中的一些人感到惊讶。
您可以轻松地对有界信号量进行子类化。
/**
* Terrible performance bounded semaphore.
**/
public class BoundedSemaphore extends Semaphore {
private static final long serialVersionUID = -570124236163243243L;
final int bound;
public BoundedSemaphore(int permits) {
super(permits);
bound=permits;
}
@Override
synchronized public void acquire() throws InterruptedException {
super.acquire();
}
@Override
synchronized public boolean tryAcquire() {
return super.tryAcquire();
}
@Override
synchronized public void release() {
if( availablePermits()<bound){
super.release();
}
}
@Override
synchronized public void acquire(int count) throws InterruptedException {
super.acquire(count);
}
@Override
synchronized public boolean tryAcquire(int count) {
return super.tryAcquire(count);
}
@Override
synchronized public void release(int count) {
if( availablePermits()<bound){
super.release(bound-availablePermits());
}
}
}
答案 5 :(得分:-1)
也许最后一行“信号量不仅限于它创建的许可证数量”,这是你的困惑之源。
使用固定的许可集初始化创建时的信号量。然后,这成为信号量在该信号量的生命期内的任何时间可以同时分配的最大许可数。除非重新初始化信号量,否则无法动态增加此数字。
引用行(来自JCIP)的含义是:首先,信号量如何工作的语义不仅限于发布和重新获得许可的细节 - 这体现在任何线程都可以访问信号量可以释放许可证(即使这个帖子在第一时间没有许可证)
其次,您可以通过调用reducePermits(int)
方法动态降低信号量的最大许可。