"公平"和"不公平"锁之间的内部存储差异



具有类Reentrant(true(锁的Lock接口的工作方式是使用BlockingQueue来存储想要获取锁的线程。这样一来,"先来先出"的线程——FIFO。一切都清楚了。

但是"不公平的锁"或ReentrantLock(false(会去哪里呢。它们的内部实现是什么?操作系统如何决定现在要选择哪个线程?最重要的是,现在这些线程也存储在队列中吗?(他们一定在某个地方(

ReentrantLock不使用BlockingQueue。它在幕后使用了AbstractQueuedSynchronizer的非公共子类。

AbstractQueuedSynchronizer类,正如其文档所述,维护"先进先出(FIFO(等待队列"。这种数据结构对于公平锁和不公平锁是相同的。这种不公平并不意味着锁会改变排队等待线程的顺序,因为这样做没有任何好处。

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

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

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

在这方面的另一个有趣的点是,ReentrantLock实现的无参数tryLock()将是不公平的,即使在锁处于公平模式的情况下也是如此。这表明不公平不是等待队列的属性,而是对进行新锁定尝试的到达线程的处理。

即使此锁已设置为使用公平排序策略,对tryLock()的调用也将立即获取可用的锁,无论其他线程当前是否正在等待该锁。这个";驳船运输";行为在某些情况下是有用的,即使它破坏了公平。

最新更新