ReentrantLock源码分析

先看 ReentrantLock 的类图 ReentrantLock.png

ReentrantLock 实现了 Lock 接口来完成加锁、释放锁等基本功能。

内部类Sync实现了 AQS 完成具体的锁独占、排队、释放等逻辑。 并提供了公平锁和非公平锁两种方式。

# 构造函数

    public ReentrantLock() {
        sync = new NonfairSync();
    }
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
1
2
3
4
5
6

无参构造函数默认使用非公平锁,也可通过有参构造函数指定使用公平锁。

# 公平锁与非公平锁

两者都是继承自内部类 Sync 。并且分别重写了 lock 和tryrelease 方法,这也就是两则的区别之处。

# 非公平锁

final void lock() {
    //cas尝试获取锁 当前资源未被加锁情况下,有可能加锁成功
    //加锁失败的情况 1.已被其他线程独占,2. 已被当前线程独占
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}
public final void acquire(int arg) {
    //再次尝试加锁失败则添加到等待队列
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}        

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

非公平锁在加锁时,使用 cas 直接尝试抢占锁, 抢占失败,再将锁加入等待队列。

# 公平锁

final void lock() {
    acquire(1);
}

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;
}

public final boolean hasQueuedPredecessors() {

    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

公平锁在抢占锁时,会先检查等待队列是否为空,或者当前线程位于等待队列队首,符合这一条件才能进行抢占。

上次更新: 2023/04/09, 16:34:32
最近更新
01
go-admin-ui项目仿写练手1-登录页
06-29
02
maven依赖问题
06-17
03
JVM相关命令
02-21
更多文章>