ReentranLock源码解析

    重入锁ReentranLock,它表示该锁能够支持一个线程对资源的重复加锁。除此之外,该锁还支持获取锁时的公平性和非公平性选择。

一、属性变量

private final Sync sync;

    定义在ReentranLock中的一个类,该类实现了AQS。并且有两个子类,分别是公平锁和非公平锁。根据需要可以创建不同的锁。

二、内部类

1、Sync类

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;
    abstract void lock();
    //非公平锁进行获取同步状态
    final boolean nonfairTryAcquire(int acquires) {
    }
    //释放同步状态
    protected final boolean tryRelease(int releases) {
    }
    //锁是否被当前线程独占
    protected final boolean isHeldExclusively() {
    }
    //监视器
    final ConditionObject newCondition() {
        return new ConditionObject();
    }
}

2、NonfairSync类

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;
    //非公平的获取同步状态
    final void lock() {
    }
    //非公平的释放同步状态
    protected final boolean tryAcquire(int acquires) {
    }
}
    顾名思义,这是非公平锁的具体实现

3、FairSync类

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;
    //公平的获取同步状态
    final void lock() {
    }
    //公平的释放同步状态
    protected final boolean tryAcquire(int acquires) {
    }
}

    OK,这个就是公平锁的具体实现

三、非公平锁获取与释放同步状态

    1、非公平获取锁

final void lock() {
    //尝试获取锁
    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();
}
final boolean nonfairTryAcquire(int acquires) {
    //获取当前线程
    final Thread current = Thread.currentThread();
    //获取当前状态
    int c = getState();
    //如果当前状态等于0,说明可以获取同步状态
    if (c == 0) {
        //如果成功获取同步状态,则将该锁设置为当前线程独占
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //如果锁状态不为0,说明有线程获取了该锁,这个线程可能是当前线程,也可能是其他线程,
    // 这里判断获取锁的线程是否为当前线程
    //如果是当前线程,说明重入
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        //重入次数加1
        setState(nextc);
        return true;
    }
    //没有锁可获取并且获取锁的线程不是当前线程
    return false;
}

    非公平的获取锁的步骤大致如下:

        当前线程快锁的获取锁,获取失败则调用acquire方法去获取锁,acquire方法中先调用nonfairTryAcquire方法来获取锁。

        tryfairTryAcquire方法先判断当前锁是否可获取,如果可获取则获取锁,不然判断当前线程是否要重入锁,如果是则重入。不然获取失败则构造同步节点加入到同步队列。

    2、公平锁的获取锁

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; 
    Node h = head;
    Node s;
    //判断当前节点是否有前驱节点存在
    return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
}

    非公平锁和公平锁代码比较,唯一不同的地方为判断条件多个hasQueuedPredecessors方法,这个方法用来判断同步队列中当前节点是否有前驱节点,如果方法返回true,则表示有线程比当前线程更早地请求获取锁,因此要等待前驱线程获取锁并释放锁后才能继续获取锁。

    3、锁的释放

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
//如果tryRelease返回true,则唤醒后继线程
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    //如果当前线程不是占有锁的线程,则抛出异常(也就是释放锁时必须获取锁)
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    //如果释放成功,将独占锁的线程清空
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

在最后说一下,没有搞懂AQS之前,先去看AQS,看懂这些实现都so easy,不然很头疼。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值