1.公平锁与非公平锁
上一篇锁入门当中,我们简单分享了常见锁的分类,有朋友看了问说:锁分类中常见的还有公平锁与非公平锁,能不能也说一下。
那么原本这一篇想要分享Lock接口分析的,干脆我们补充一下关于公平锁与非公平锁吧,关于Lock接口的分析,我们放到下一篇再一起来看。
公平可以说是芸芸众生都追求的真理,我们都是芸芸众生中的一员,自然也都期望公平。那要这么说,有公平锁就够了,java的设计者为什么还非要设计非公平锁呢?下面我们就来一起尝试分析分析。
首先,我们先从锁的基本原理开始。假设现在有三个线程:线程A、线程B、线程C;有一把锁:锁L;通常情况下,我们看一下三个线程并行获取锁L,需要怎么协调处理呢?我们都知道一把锁,同一时刻是只能一个线程持有的。那么假设线程A持有了锁L,则线程B、线程C只能等待;同理如果线程B、或者线程C持有了锁,那么另外两个线程都只能等待。即总结出来一句话:多个线程并行获取锁,当某个线程获取到锁以后,那么其它线程需要排队等待。注意这里的排队等待四个字,这便是公平锁了。我们可以看一个图,形象一些:
公平锁比较好理解,我们来看一下公平锁存在什么问题,分析清楚以后,相信你就可以更好的理解非公平锁了。你看,在公平锁这里强调的是:排队。即要讲究先来后到,但是我们知道,高并发下线程的等待唤醒是需要时间成本的,比如说:线程A持有了锁L,那么线程B、线程C都在排队等待锁L;当线程A释放锁L以后,cpu线程调度需要唤醒线程B,注意就是这个唤醒是有时间成本的,相当于有个空档期,你可以这么去理解。
那么我们能不能把这个空档期利用上呢?如果能够利用上,则可以有效提升应用的处理能力(性能)。比如说:当线程A释放锁L的时刻,刚好有一个线程D要获取锁L;那么我们能不能说直接把锁L给线程D,先不要唤醒等待队列中的线程B、线程C......。这样一来,对于应用来说,就不存在唤醒线程的空档期了,即有效提升了应用的处理能力。关于非公平锁,我们也形象的看一个图:
到这里我们稍微总结一下:
- 公平锁与非公平锁,公平锁强调在多线程并发获取同一个锁的时候,当一个线程持有了锁后,其它的线程需要排队等待,特点是有序,因此公平
- 非公平锁,则是强调避免因为唤醒等待线程的的时间成本,充分利用唤醒线程的空档期,提升应用处理能力,特点是可以允许插队,因此非公平
- 需要注意:非公平锁的插队,并不是简单粗暴的插队,事实上非公平锁,强调的是在合适的时机插队。关于这点,你先留一个印象,我们后面通过案例的方式来演示一下公平锁与非公平锁