【并发编程】公平锁与非公平锁的区别

在Java的concurrent包中,公平锁与非公平锁是很常见的概念,ReentrantLock、ReadWriteLock默认都是非公平模式。

非公平锁的效率为什么会高于公平锁呢?那么公平锁与非公平锁又有什么区别呢?、

概念解释

首先从字面意思理解,公平锁自然是遵循FIFO(先进先出)原则的,先到的线程会优先获取资源,后到的会进行排队等待,而非公平锁是不遵循这个原则的。

图解

tip: 该图出自 https://www.jianshu.com/p/f584799f1c77

源码解析

    public ReentrantLock() {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
  • 可以看到ReentrantLock默认使用的是非公平锁。
  • 公平锁和非公平锁分别使用了FairSyncNonfairSync实现
非公平锁
final boolean nonfairTryAcquire(int acquires) {
	final Thread current = Thread.currentThread();
	int c = getState();
	if (c == 0) {
		if (compareAndSetState(0, acquires)) {
			setExclusiveOwnerThread(current);
			return true;
		}
	}
	else if (current == getExclusiveOwnerThread()) {
		int nextc = c + acquires;
		if (nextc < 0) // overflow
			throw new Error("Maximum lock count exceeded");
		setState(nextc);
		return true;
	}
	return false;
}
  • 可以看到非公平锁里,判断当前锁占用状态==0直接会进行compareAndSetState尝试获取锁。若此时有线程排队,可能争夺不过资源。所以这是非公平的
  • 在非公平锁里,因为可以直接compareAndSetState来获取锁,不需要加入队列,然后等待队列头线程唤醒再获取锁这一步骤,所以效率较快
公平锁
protected final boolean tryAcquire(int acquires) {
	final Thread current = Thread.currentThread();
	int c = getState();
	if (c == 0) {
		if (!hasQueuedPredecessors() &&
			compareAndSetState(0, acquires)) {
			setExclusiveOwnerThread(current);
			return true;
		}
	}
	else if (current == getExclusiveOwnerThread()) {
		int nextc = c + acquires;
		if (nextc < 0)
			throw new Error("Maximum lock count exceeded");
		setState(nextc);
		return true;
	}
	return false;
}
  • 在公平锁里,判断当前锁占用状态==0后,会继续判断hasQueuedPredecessors,即当前队列是否有排队的情况,如果没有才会尝试获取锁
  • 这样可以保证遵循FIFO的原则,每一个先来的线程都可以最先获取到锁,但是增加了上下文切换与等待线程的状态变换时间。所以效率相较于非公平锁较慢。
posted @ 2020-06-03 13:59  faylinn  阅读(7296)  评论(2编辑  收藏  举报
、、、