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

  • 如果将它们正确封装,则该机制将是坚如磐石。

    07-24 19:20