正如其他答案中所解释的,有一种解决方案可以使您的代码具有原子性。但是,不能保证它会在一般设置中解决问题,因为此代码不可能在所有情况下都是正确的。
许可证要么由使用它们的活动释放,在这种情况下代码是多余的:信号量将自然补充,或者它们不会,在这种情况下你将需要那段代码,它是安全的,只要你不会用它做任何奇怪的事情。
请注意,您声明您希望限制每个时间段(此处为一分钟)的活动速率,但您必须考虑到活动可能持续超过一分钟。您可以在此处限制两种不同的事情:
- 每个量程开始的活动数量,
- 在一个量程中运行的活动数量
如果您希望限制第一个,那么您将需要您的代码来重新填写许可证,并让活动保留他们的许可证。如果要处理第二种情况,则必须强制活动在启动和终止时分别获取和释放其许可。
如果您担心某些活动滥用信号量,请禁止在活动代码本身中使用它。实际上,速率限制与活动语义完全正交,最好将该功能与活动主代码分开。因此,您应该使用代码包装任何计划的活动来处理信号量:
class RateLimitedRunnable implements Runnable {
Runnable runnable;
RateLimitedRunnable(Runnable r) { runnable = r; }
void Run() {
semaphore.acquire();
runnable.run();
semaphore.release(); // remove if only limiting starts
}
}
上面的示例(未经测试)代码描述了远离实际活动的信号量使用的可能处理,从而消除了任何潜在的误用。如果内部活动需要访问信号量,它应该只检索其当前状态,并且可以设计一个 ad-hoc 接口来提供这种有限的访问。
注意:我在这里使用“活动”一词作为线程或进程的意思,因为关于信号量使用的讨论比Java的上下文更普遍。