'fair' 和 'unfair' 锁之间的内部存储差异

Difference in internal storing between 'fair' and 'unfair' lock

带有 class 可重入(真)锁的 Lock 接口的工作方式是它使用 BlockingQueue 来存储想要获取 锁的线程。以那种方式线程'came first, go out first'-FIFO。都清楚了。

可是'unfair locks'去哪儿了,还是ReentrantLock(false)。他们的内部实现是什么? OS 如何决定现在选择哪个线程?最重要的是,现在这些线程是否也存储在队列中或存储在何处? (他们一定在某处)

幕后的classReentrantLock does not use a BlockingQueue. It uses a non-public subclass of AbstractQueuedSynchronizer

AbstractQueuedSynchronizerclass,如其文档所述,维护“一个first-in-first-out(FIFO)等待队列”。这个数据结构对于公平锁和非公平锁是一样的。不公平并不意味着锁会改变排队等待线程的顺序,因为这样做没有任何好处。

关键区别在于非公平锁允许 lock 尝试在锁刚被释放时立即成功,即使有其他线程等待锁的时间更长。在那种情况下,队列甚至不涉及超车线程。这比将当前线程加入队列并使其进入等待状态,同时从队列中删除等待时间最长的线程并将其状态更改为“可运行”更有效。

当锁不可用时,一个线程试图获取它,该线程将被添加到队列中,此时,它与公平锁和非公平锁没有区别(除了其他线程可能会在没有排队的情况下超越它)。由于未指定非公平锁的顺序,它可以在后台使用后进先出数据结构,但两者只有一个实现代码显然更简单。

另一方面,synchronized不支持公平获取,有一些JVM实现使用后进先出结构。这可能会从一个版本更改为另一个版本(或者甚至是相同的,作为某些 JVM 选项或环境方面的副作用)。

这方面的另一个有趣的一点是,ReentrantLock 实现的 parameterless tryLock() 将是不公平的,即使锁在其他方面处于公平模式。这表明不公平不是这里的等待队列属性,而是对进行新锁尝试的到达线程的处理。

Even when this lock has been set to use a fair ordering policy, a call to tryLock() will immediately acquire the lock if it is available, whether or not other threads are currently waiting for the lock. This "barging" behavior can be useful in certain circumstances, even though it breaks fairness.