公平锁与非公平锁理论
本文知识:
公平锁与非公平锁理论
AQS的理论与原理讲解
公平锁与非公平锁原理讲解
ReentrantLock的使用
非公平锁饥饿效应解决方法
在上篇中分析了Java并发编程中悲观锁与乐观锁的实现算法,并分析了原子类中使用CAS算法实现乐观锁以及ABA、自旋等问题。
延续上篇继续导论Java ReentrantLock锁,如果实现公平锁与非公平锁。
前言
公平锁:多个线程申请锁时是相对公平的,在申请锁时如果有其它线程已经占用了锁,则进行排队等待处理。
非公平锁:多个线程申请锁时相对不公平,与公平锁相同,都会存在排队的情况,但对于一个新线程需要获取锁时不是先排队等待,而是先尝试获取锁,不成功时再进入队列排队等待。
AQS
在分析公平锁与非公平锁之前,先来讲讲AQS这个家伙。
AQS全称AbstractQueuedSynchronizer,它实现了锁的等待队列、锁的获取与释放;它是一个抽象的实现。
AQS使用链接实现一个FIFO队列,使用state表示锁的状态,当state大于0时表示当前已经有线程占用锁了,在Thread1已经占用锁后再重复调用加锁操作时state会+1,这样就实现了重入锁,每次释放锁时state会-1,为0时完全释放锁,队列中等待的第一个线程可以开始获取锁。
AQS更多的内容后面再单独写一篇详细的文章进行分析,今天转入正题公平锁与非公平锁。
公平锁
线程在获取锁时以公平的形式进行,没有线程占用锁时可以直接获取锁成功,已经有线程占用锁或者已经有人在排队时将进入队列排队等待。公平锁不会出现饥饿效应,所有的线程都有可以获取到锁,但对CPU唤醒线程的开销较大,线程越多开销越大。下面用一个售票排队的例子来解释公平锁:
售票窗里的售票员负责卖票,相当于AQS中的state变量,一个购票人一次可以买n张票,出队了还需要买票就需要重复排队,新购票人来买票时看当前售票窗有没有人正在买票,没有就可以直接买票,有就需要排队,排队就相当于AQS中的FIFO队列。就样的过程就是公平锁实现的思想,票是资源由售票员进行管理与售卖,买票需要有秩序,不能插队,让所有买票的人都是公平的,谁先来谁先买。
非公平锁
线程获取锁时以不公平的方式进行,公平锁获取锁的方式是进入队列排队取锁,而非公平锁与公平锁在的区别只要就在排队上,非公平锁可以在队列的第一位的位置进行一次插队,插队成功就可以先获取锁,没有插队成功就需要像公平锁一样进行排队等待获取锁。非公平锁可能什么出现饥饿效应,队列中等待的线程与新来获取锁的线程在锁获取上是不公平的,有插队这一行为,正是因为有这一行为就有可能导致队列中等待的线程等待时间过长而出现