Semaphore.release()
的(Oracle) javadoc包括:
这是一个艰难的 promise 吗?这意味着如果线程A在acquire()
中等待,而线程B这样做:
sem.release()
sem.acquire()
然后release()
应该将控制权传递给A,而B将被阻止在acquire()
中。如果只有这两个线程可以保留信号量,并且doc语句在形式上正确,那么这是一个完全确定性的过程:之后,A将获得许可,而B将被阻止。但这不是真的,或者至少在我看来确实如此。我没有在这里打扰SSCCE,因为我真的只是在寻找确认以下信息的地方:
适用竞争条件:即使线程A正在等待许可,但在线程A释放后,线程B可以立即重新获取它,而线程A仍被阻塞。
如果有什么不同,这些是“公平的”信号量,我实际上是在kotlin工作。
最佳答案
在对Slaw问题的评论中,指出了the documentation的其他内容:
这里的重点是acquire()
是一个具有开头和结尾的可中断函数。在其异常期间的某个时刻,调用线程会保护公平队列中的一个点,但是与另一个线程同时访问同一函数有关时,仍然不确定。将此点称为X并考虑两个线程,其中一个线程持有信号量。在某个时候,另一个线程调用:
sem.acquire()
无法保证调度程序不会在到达点X之前将acquire()
中的线程放在一边。 如果所有者线程然后执行此操作(例如,这可能旨在用作某种同步检查点或屏障控制): sem.release()
sem.acquire()
它可以简单地释放并获取信号量,而不必被另一个线程获取,即使该线程已经输入了acquire
。在调用之间注入(inject)
Thread.sleep()
或yield()
可能经常有效,但这不是保证。要创建这样一个具有保证的检查点,您需要两个锁/信号灯进行交换:semA
。 semB
,然后等待semA
。 semA
,然后等待semB
,如果另一个线程确实通过按住semA
真正在等待semB
,则会阻塞并保证客户端现在可以获取semA
。 semB
,然后释放semA
。 semB
时,它可以获取semA
并释放semB
。 如果将它们正确封装,则该机制将是坚如磐石。