如何解决“公平”和“不公平”锁之间的内部存储差异
具有Reentrant(true)锁类的Lock接口的工作方式是,它使用 BlockingQueue 存储要获取 lock 的线程。这样,“先到先出” -FIFO的线程。一切都清楚了。
但是“不正当锁”在哪里,或者ReentrantLock(false)。它们的内部实现是什么? OS如何决定现在选择哪个线程?最重要的是,这些线程现在也存储在队列中还是在哪里? (它们必须在某处)
解决方法
类ReentrantLock
不使用BlockingQueue
。它在幕后使用了AbstractQueuedSynchronizer
的非公开子类。
AbstractQueuedSynchronizer
类,如其文档所述,维护“先进先出(FIFO)等待队列”。对于公平锁和不公平锁,此数据结构相同。不公平的做法并不意味着锁会改变排队的等待线程的顺序,因为这样做没有任何好处。
关键区别在于,不公平的锁定允许lock
尝试在锁定刚刚释放时立即成功执行,即使有其他线程在等待更长的时间。在这种情况下,超线程甚至不涉及该队列。这比将当前线程添加到队列并将其置于等待状态,同时从队列中删除最长的等待线程并将其状态更改为“可运行”更为有效。
当该锁尚不可用时,线程将尝试获取该锁,该线程将被添加到队列中,此时,对其的公平锁和不公平锁之间没有区别(除非其他线程可能超越它而不被排队)。由于尚未为不正确的锁定指定顺序,因此可以在后台使用LIFO数据结构,但是为这两种情况仅使用一个实现代码显然会更简单。
另一方面,对于synchronized
,它不支持公平获取,有一些使用LIFO结构的JVM实现。这可能会从一个版本更改为另一个版本(或者甚至具有相同版本,这是某些JVM选项或环境方面的副作用)。
在这方面的另一个有趣的点是,即使在锁定处于公平模式的情况下,ReentrantLock
实现的parameterless tryLock()
也将是不公平的。这表明不公平不是这里等待队列的属性,而是对进行新锁定尝试的到达线程的处理。
即使将此锁设置为使用公平的订购策略,只要有可用的锁,对
tryLock()
的调用都会立即获取,无论当前是否正在等待其他线程锁。即使破坏公平性,这种“讨价还价”的行为在某些情况下还是有用的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。