什么是公平锁?什么是非公平锁?
公平锁:多个线程按照申请锁的先后顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能获得锁。
非公平锁:多个线程去获得锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。
优缺点比较
公平锁
优点:所有的线程都能够得到资源,不会饿死在队列中。
缺点:吞吐量会下降很多,队列里面除了第一个线程,其它线程都会阻塞,CPU唤醒阻塞线程的开销会很大。
非公平锁
优点:可以减少CPU唤醒线程的开销,整体的吞吐率提高。
缺点:可能导致队列中的线程一直获取不到锁或者长时间获取不到锁,导致饿死。
源码体现
在ReentrantLock中就提供了公平锁和非公平锁两种模式(默认是非公平实现)。
公平锁实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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; }
|
1 2 3 4 5 6 7 8 9 10 11 12
|
public final boolean hasQueuedPredecessors() { Node t = tail; Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
|
公平锁只有在队列为空,或者自己为队头的时候才会尝试去修改state,当修改成功后则直接拿到了锁,否则进入排队。
非公平锁实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
|
非公平锁当state==0,就会立即去尝试CAS修改state,修改成功了则直接拿到了锁,否则加入阻塞队列。