【问题标题】:Why is Java's Semaphore fairness an argument to the constructor rather than the acquire() / tryAcquire() calls?为什么 Java 的信号量公平性是构造函数的参数,而不是 acquire() / tryAcquire() 调用?
【发布时间】:2015-06-05 19:17:52
【问题描述】:

我完全没有理由认为这不是每次调用选项。信号量可能在具有不同公平性要求的不同代码路径(主检查进度/工作人员从队列中抓取工作/...)中被关闭。也许在一种情况下,我们希望公平地检查进度,而在另一种情况下,如果运行中的工作人员只有足够的工作量,我们希望相同的少数工作人员工作,以优化 L1 缓存命中等)

【问题讨论】:

  • 我不明白这个问题。线程 1 请求公平并得到它(意味着进入操作系统睡眠并像其他服务员一样竞争以获得锁)。线程 2 没有拿到锁,因为他愿意在不睡觉的情况下抓住锁,即使有服务员如果他继续松手并紧紧地抓住,就永远不会赢得比赛。公平的意思是有服务员就排队,没有别的。不要将它与韦伯斯特的定义混淆。它与此上下文无关。
  • 我说语义不正确。你说阅读文档。如果我们想要任何线程排队,没有理由强制每个线程排队。因此,这是一个任意限制。如果程序员想要你的方式,他可以使所有调用都公平。您还必须证明他必须穿制服的原因之一。至于 FIFO,您无法控制它。操作系统将决定谁被唤醒。您只需选择进入操作系统睡眠,以及它应该唤醒多少。你可以期待一个先进先出。但除非你能告诉我在 Linux 中的哪个位置(man 7 futex 或 man 2 futex)它说 FIFO,否则 Java 也不能保证。
  • 它与 linux 上的 futex 有关,因为它是获得操作系统提供的抢占式多任务处理的唯一方法。如果您不相信我,请在紧密循环中创建锁定争用并 strace 以查看在争用情况下 Java 对操作系统的系统调用。至于我创建“我自己的”,语义只有在有意义时才应该创建限制。你能说出这个限制存在的一个原因吗?为什么我不能在每次调用时指定这个参数?这是唯一的问题,正如我在发布之前所预料的那样,没有人能够提出一个好的理由。
  • 顺便说一句,如果您真的想尝试 strace'ing 它,请记住要从子线程获取系统调用,您需要 strace -f

标签: java semaphore


【解决方案1】:

即使您在构造函数中将fair 设置为true,tryAcquire 也是不公平的。

即使此信号量已设置为使用公平排序策略, 致电tryAcquire() 将立即获得许可,如果有人 是否可用,无论其他线程当前是否正在等待。这个 “闯入”行为在某些情况下可能很有用,即使 它打破了公平。如果你想尊重公平设置,那么 使用tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) 这几乎是等效的(它还检测到中断)。

-- https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html#tryAcquire()


我认为这种行为足以启用您概述的场景(检查进度与抓取工作)。

【讨论】:

  • 谢谢。但我认为这是两件不同的事情。在一个理智的实现中,tryAcquire() 应该与 acquire() 不同,因为它返回失败而不是进入睡眠状态。如果有服务员(比赛),公平与它是否在没有睡眠的情况下获得锁有关。所以公平(如果有的话)首先发挥作用,如果它没有在用户空间中获得锁定,try 使它不是休眠而是失败。换句话说,在一个理智的实现中,我应该能够: while(sem.tryAcquire(fair)) { sem.grant(); } 并且永远不要阻止自己,不要饿死别人。干杯。
猜你喜欢
  • 2015-06-10
  • 2012-06-28
  • 1970-01-01
  • 2019-11-07
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 2017-09-04
相关资源
最近更新 更多