内部存储在“公平"和“不公平"锁之间的差异 [英] Difference in internal storing between 'fair' and 'unfair' lock

查看:47
本文介绍了内部存储在“公平"和“不公平"锁之间的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有Reentrant(true)类锁的Lock接口的工作方式是,它使用 BlockingQueue 存储要获取 lock 的线程.这样,先到先出" -FIFO的线程.一切都清楚了.

但是不正当锁"在哪里,或者ReentrantLock(false).它们的内部实现是什么?OS如何决定现在选择哪个线程?最重要的是,这些线程现在是否也存储在队列中或存储在何处?(它们必须在某处)

解决方案

AbstractQueuedSynchronizer 类维护先进先出(FIFO)等待队列".对于公平锁和不公平锁,此数据结构相同.不公平的做法并不意味着锁会改变排队的等待线程的顺序,因为这样做没有任何好处.

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

当该锁尚不可用时,线程将尝试获取该锁,该线程将被添加到队列中,此时,对其的公平锁和不公平锁之间没有区别(除非其他线程可能超越它而不会被排队).由于尚未为不公平的锁定指定顺序,因此可以在后台使用LIFO数据结构,但是为这两种情况仅使用一个实现代码显然会更简单.

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

这方面的另一个有趣之处在于,

The way Lock interface with class Reentrant(true) lock works is that it uses BlockingQueue to store Threads that want to acquire the lock. In that way thread that 'came first, go out first'-FIFO. All clear about that.

But where do 'unfair locks' go, or ReentrantLock(false). What is their internal implementation? How does OS decide which thread now to pick? And most importantly are now these threads also stored in a queue or where? (they must be somewhere)

解决方案

The class ReentrantLock does not use a BlockingQueue. It uses a non-public subclass of AbstractQueuedSynchronizer behind the scenes.

The AbstractQueuedSynchronizer class, as its documentation states, maintains "a first-in-first-out (FIFO) wait queue". This data structure is the same for fair and unfair locks. The unfairness doesn’t imply that the lock would change the order of enqueued waiting threads, as there would be no advantage in doing that.

The key difference is that an unfair lock allows a lock attempt to succeed immediately when the lock just has been released, even when there are other threads waiting for the lock for a longer time. In that scenario, the queue is not even involved for the overtaking thread. This is more efficient than adding the current thread to the queue and putting it into the wait state while removing the longest waiting thread from the queue and changing its state to "runnable".

When the lock is not available by the time, a thread tries to acquire it, the thread will be added to the queue and at this point, there is no difference between fair and unfair locks for it (except that other threads may overtake it without getting enqueued). Since the order has not been specified for an unfair lock, it could use a LIFO data structure behind the scenes, but it’s obviously simpler to have just one implementation code for both.

For synchronized, on the other hand, which does not support fair acquisition, there are some JVM implementations using a LIFO structure. This may change from one version to another (or even with the same, as a side effect of some JVM options or environmental aspects).

Another interesting point in this regard, is that the parameterless tryLock() of the ReentrantLock implementation will be unfair, even when the lock is otherwise in fair mode. This demonstrates that being unfair is not a property of the waiting queue here, but the treatment of the arriving thread that makes a new lock attempt.

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.

这篇关于内部存储在“公平"和“不公平"锁之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆