我的原则:先会用再说,内部慢慢来
一、概念
- 公平锁: 遵循FIFO,先来先服务的原则。
- 非公平锁: 哄抢锁,谁先抢到服务谁。
二、ReentrantLock 架构
三、FailSync 与 NonfairSync 核心代码区别
- 根据 AQS 实现类的不同,FairSync + NonfairSync 的tryAcquire实现不同
- Sync#nonfairTryAcquire 非公平模式获取锁方法
- FairSync#tryAcquire 公平模式获取锁方法
- AbstractQueuedSynchronizer#acquire 方法
public final void AbstractQueuedSynchronizer#acquire(int arg) {
/*
* 根据 AQS 实现类的不同,FairSync + NonfairSync 的tryAcquire实现不同
* 1. NonfaireSync 在 tryAcquire 很大几率获得锁 ,不往下走了
* 2。 FairSync 在 tryAcquire ,若遇到Sync队列有Node,那么就直接获取失败,进入 acquireQueued 去排队。
*/
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- Sync#nonfairTryAcquire 非公平模式获取锁方法
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 公平锁与非公平锁区别就在这,非公平锁模式下,一会机会直接就去争夺锁了。无需FIFO
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;
}
- FairSync#tryAcquire 公平模式获取锁方法
protected final boolean FairSync#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;
}
四、代码 demo
- FairSync 模式
public class _12_02_TestCondition {
public static void main(String[] args) throws Exception{
LockDemo lockDemo = new LockDemo();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
lockDemo.await();
} catch (Exception e) {
e.printStackTrace();
}
},"A" + i).start();
}
// 确保上面代码先执行
Thread.sleep(1000);
Scanner sc = new Scanner(System.in);
System.out.println("点击任意键唤醒线程 ...");
sc.nextLine();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
lockDemo.signal();
},"B" + i).start();
}
}
static class LockDemo{
ReentrantLock lock = new ReentrantLock(true);
Condition condition = lock.newCondition();
public void await() throws Exception{
System.out.println(Thread.currentThread().getName() + ",condition ready to lock ===");
lock.lock();
System.out.println(Thread.currentThread().getName() + ",condition ready to await ");
condition.await();
System.out.println(Thread.currentThread().getName() + ",condition ready to unlock ===");
lock.unlock();
}
public void signal(){
System.out.println(Thread.currentThread().getName() + ",condition ready to lock ");
lock.lock();
System.out.println(Thread.currentThread().getName() + ",condition ready to signal ");
condition.signal();
System.out.println(Thread.currentThread().getName() + ",condition ready to unlock ");
lock.unlock();
}
}
}
-
- FairSync 模式下输出:
A0,condition ready to lock ===
A1,condition ready to lock ===
A0,condition ready to await
A2,condition ready to lock ===
A3,condition ready to lock ===
A4,condition ready to lock ===
A1,condition ready to await
A2,condition ready to await
A3,condition ready to await
A4,condition ready to await
点击任意键唤醒线程 ...
B0,condition ready to lock
B0,condition ready to signal
B0,condition ready to unlock
B1,condition ready to lock
A0,condition ready to unlock ===
B2,condition ready to lock
B1,condition ready to signal
B1,condition ready to unlock
B3,condition ready to lock
B2,condition ready to signal
B2,condition ready to unlock
A1,condition ready to unlock ===
B4,condition ready to lock
B3,condition ready to signal
B3,condition ready to unlock
A2,condition ready to unlock ===
B4,condition ready to signal
B4,condition ready to unlock
A3,condition ready to unlock ===
A4,condition ready to unlock ===
- 改成 NonfairSync 模式
ReentrantLock lock = new ReentrantLock(); // 默认非公平锁
- NonfairSync 模式下输出
A0,condition ready to lock ===
A1,condition ready to lock ===
A2,condition ready to lock ===
A0,condition ready to await
A3,condition ready to lock ===
A3,condition ready to await
A1,condition ready to await
A2,condition ready to await
A4,condition ready to lock ===
A4,condition ready to await
点击任意键唤醒线程 ...
B0,condition ready to lock
B1,condition ready to lock
B0,condition ready to signal
B0,condition ready to unlock
B2,condition ready to lock
B2,condition ready to signal
B2,condition ready to unlock
B3,condition ready to lock
B1,condition ready to signal
B4,condition ready to lock
B1,condition ready to unlock
A0,condition ready to unlock ===
A3,condition ready to unlock ===
B3,condition ready to signal
B3,condition ready to unlock
A1,condition ready to unlock ===
B4,condition ready to signal
B4,condition ready to unlock
A2,condition ready to unlock ===
A4,condition ready to unlock ===
结论:
ReentrantLock lock = new ReentrantLock(true); 公平锁模式下,谁先 lock ,谁就先 unlock。
ReentrantLock lock = new ReentrantLock(); 非公平锁模式下,不一定。
五、番外篇
下一章节:【线程】ReentrantReadWriteLock 内部共享锁与排他锁源码分析 (十一)
上一章节:【线程】ReentrantLock + Condition 源码剖析 (九)