锁的公平性与非公平性
我们知道,在并发环境中,多个线程需要对同一资源进行访问,同一时刻只能有一个线程能够获取到锁并进行资源访问,那么剩下的这些线程怎么办呢?这就好比食堂排队打饭的模型,最先到达食堂的人拥有最先买饭的权利,那么剩下的人就需要在第一个人后面排队,这是理想的情况,即每个人都能够买上饭。那么现实情况是,在你排队的过程中,就有个别不老实的人想走捷径,插队打饭,如果插队的这个人后面没有人制止他这种行为,他就能够顺利买上饭,如果有人制止,他就也得去队伍后面排队。
对于正常排队的人来说,没有人插队,每个人都在等待排队打饭的机会,那么这种方式对每个人来说都是公平的,先来后到嘛。这种锁也叫做公平锁。

那么假如插队的这个人成功买上饭并且在买饭的过程不管有没有人制止他,他的这种行为对正常排队的人来说都是不公平的,这在锁的世界中也叫做非公平锁。


那么我们根据上面的描述可以得出下面的结论
公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的了。
锁公平性的实现
在 Java 中,我们一般通过 ReetrantLock 来实现锁的公平性
我们分别通过两个例子来讲解一下锁的公平性和非公平性
锁的公平性
public class MyFairLock extends Thread{
private ReentrantLock lock = new ReentrantLock(true);
public void fairLock(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() "正在持有锁");
}finally {
System.out.println(Thread.currentThread().getName() "释放了锁");
lock.unlock();
}
}
public static void main(String[] args) {
MyFairLock myFairLock = new MyFairLock();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName() "启动");
myFairLock.fairLock();
};
Thread[] thread = new Thread[10];
for(int i = 0;i < 10;i ){
thread[i] = new Thread(runnable);
}
for(int i = 0;i < 10;i ){
thread[i].start();
}
}
}
我们创建了一个 ReetrantLock,并给构造函数传了一个 true,我们可以查看 ReetrantLock 的构造函数
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
根据 JavaDoc 的注释可知,如果是 true 的话,那么就会创建一个 ReentrantLock 的公平锁,然后并创建一个 FairSync ,FairSync 其实是一个 Sync 的内部类,它的主要作用是同步对象以获取公平锁。

