解锁后的Java线程执行顺序

8
假设我有2个线程t1和t2,还有一个锁对象m。线程t1处于无限循环状态,在每次迭代中,它会获取m上的锁,执行一些工作,解锁m并立即重新开始。在一个迭代期间,t2请求对m的锁定,但被t1阻塞并等待。现在,当t1解锁m时,是否保证t2将获得下一个m的锁?或者t1可以在下一次迭代中悄悄超过它?
通常情况下,是否设置了等待线程的队列?如果t1拥有锁,并且所有其余想要该锁的线程按以下顺序被阻塞:t2,t3,...,那么剩余的线程会按照它们被阻塞的顺序继续执行(例如,t2运行,然后是t3等)?
(我简要查阅了Java规范,但没能找到答案。如果有,请告诉我,我会再仔细阅读。)
谢谢!(第一篇SO帖子,哇哦!)

好的,所以“公平性”是我要寻找的概念。回顾一下(如果我说错了请纠正):synchronized语句是不公平的,其中“公平”是通过以下方式定义的(来自此处):“公平锁是指线程按照请求锁的顺序获得锁。” - heycosmo
4个回答

3
是的,有一个队列,而且这个队列可能是公平的或不公平的。公平的队列更昂贵,不公平的队列速度更快(谁赢得CAS就赢得了锁)。 详细信息请查看java.util.concurrent.locks.AbstractQueuedSynchronizer
剩余的线程将按照阻塞时的顺序继续执行吗(例如,t2运行,然后是t3,等等)?
主要问题在于它们是同时并发执行的,你不能真正定义在同一时间执行的两个事件的顺序。但是对于公平的锁(不建议使用,因为会增加额外的成本),任何成功排队等待锁的线程最终都会获得锁。

获取锁的竞争与获取已释放锁的竞争无关。 - heycosmo
@heycosmo,解锁后解除阻塞的代码位于AbstractQueuedSynchronizer.unparkSuccessor中;虽然线程被保留在队列中,但解除阻塞的线程并不能确切地获得锁定。要解除阻塞的线程保存在后继节点中,通常只是下一个节点。但如果已取消或显然为空,则从尾部向后遍历以找到实际未取消的后继节点。打开类并阅读描述如何工作,其中包括从等待队列节点类开始的信号演示。 - bestsss
除非明确指定,否则即使线程已被唤醒,它仍必须与试图获取锁的其他线程竞争(即使某些阻塞线程经历了间歇性的唤醒,也可以参与)。在锁被释放并唤醒下一个继承者线程的短暂时刻,锁才能被获取。 - bestsss
@heycosmo,你是指使用synchronized关键字的那个吗?它们确实使用了(至少在hotspot中)类似的策略,但还有更多,包括偏向锁定,使得当锁未争用时,synchronized(xxx)非常便宜(只需几个CPU时钟,仅需加载/比较)。Java本地锁(hotspot / azul,假设JVM供应商的其余部分也是如此)不是使用本机代码实现的,而是在C中使用类似的算法。 - bestsss
@heycosmo,我想我被“unlock”和“freed lock”这两个词所误导了,Java中它们被称为“monitors”,并且它们的命令是monitorEnter/monitorExit(基本上就是synchronized发生的事情)。 - bestsss
显示剩余3条评论

0

不,没有这样的保证。你可以建议Java使用可重入锁对象实现公平性, 但这只是一种建议而不能保证任何顺序。

通常情况下,你不能保证这样的顺序(除非有显式同步来实现它),因为t2在获取线程之前可能已经被中断,而且由操作系统决定哪个线程被恢复。


0

对于大多数情况,没有保证。您会注意到一些java.util.concurrent抽象提供了“公平锁”的选项 - 这更或多或少地保证每个等待锁的线程最终都会被调用(而不是特定的顺序)。没有公平性,就没有保证。另一方面,公平性非常昂贵。(请参见Java Concurrency In Practice的一些基准测试),通常,概率可能性已经足够好了。


0

您可以使用公平的信号量来保证顺序。标准内置的Java锁/监视器不是公平的,不能以公平的方式排队订单。

Semaphore sem = new Semaphore(1, true);

//usage:
sem.acquire();
try {
  //holding a lock
  //of course both threads share the same semaphore
} finally {
  sem.release();
}

理论上,使用锁定机制后,T1 可以在释放锁之后的下一次迭代中再次获取锁,尽管此时 T2 已经等待它了。这种情况不太可能发生,但是仍有可能。


1
当使用公平选项创建时,ReentrantLock和Semaphore的代码实际上是相同的。您可以查看java.util.concurrent.Semaphore.FairSync和java.util.concurrent.locks.ReentrantLock.FairSync。 - bestsss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接