公平锁与非公平锁的含义都很明白,公平锁必须排队获取锁,锁的获取顺序完全根据排队顺序而来,而非公平就是谁抢到是谁的
。
我们都知道AQS中的锁获取,如果首次获取失败会进入到内部的同步队列中阻塞等待,只有前面的节点唤醒当前节点才能去尝试获取锁
从我之前的博客内容可知,锁获取的核心,实际上是在try方法中定义的
,在节点从阻塞中醒来时,都会用try方法来获取锁
,而公平与否在try方法中体现
,即在公平锁中,try获取的前提时需要没有存在前驱节点的,而非公平锁就没有这个限制
。
但是!同步队列不是FIFO的吗,它们入队排好顺序并且按照顺序一个一个的醒来
,只有醒来的才有机会去获取锁,才能去执行try方法,这不还是公平的吗?
解答
线程在do方法中获取锁时,会先加入同步队列,之后根据情况再陷入阻塞。当阻塞后的节点一段时间后醒来时,这时候来了新的更多的线程来抢锁,这些新线程还没有加入到同步队列中去,也就是在try方法中获取锁。
在公平锁下,这些新线程会发现同步队列中存在节点等待,那么这些新线程将无法获取到锁,乖乖去排队;
而在非公平锁下,这些新线程会跟排队苏醒的线程进行锁争抢,失败的去同步队列中排队。
因此这里的公平与否,针对的其实是苏醒线程与还未加入同步队列的线程
而对于已经在同步队列中阻塞的线程而言,它们内部自身其实是公平的,因为它们是按顺序被唤醒的,这是根据AQS节点唤醒机制和同步队列的FIFO特性决定的