JUC——ReentrantLock

ReentrantLock是基于AQS来实现的,所以如果想对它有所了解,最好先熟悉一下AQS的内容,它继承了Lock接口,Lock接口定义了加锁释放锁的方法;
ReentrantLock支持公平锁和非公平锁两种加锁方式,而不像synchronized只支持一种非公平锁;并且ReentrantLock也支持中断非中断加锁;

1. 公平锁

ReentrantLock内部有三个内部类,Sync、NonfairSync、FairSync;其中FairSync是实现公平锁的子类,而NonfairSync和FairSync继承自Sync分别实现非公平锁和公平锁;
new ReentrantLick()时,默认创建的是NonfairSync,如果想创建一个公平锁,只需要new ReentrantLock(true)

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

1.1 加锁

final void lock() {
    acquire(1);
}
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 如果c==0,表示当前没有人加锁,当前线程可以进行加锁处理;
    if (c == 0) {
        // 如果不需要排队,则修改state值,修改成功表示当前线程获得到锁;
        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;
}
// 用于判断是否需要排队,返回false不用排队,否则需要排队
public final boolean hasQueuedPredecessors() {
    // 
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    return h != t && // head=tail=null 不需要排队,另外一种情况是只有一个节点,并且head=tail 只有一个节点也是不需要排队的,因为队列中的第一个节点是不需要排队的;
        ((s = h.next) == null || s.thread != Thread.currentThread()); 
}

1.2 解锁

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;
}
// 释放锁
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 如果c!=0表示有锁重入
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    // 释放锁是在获取锁的情况下进行的,所以这里不需要CAS
    setState(c);
    return free;
}

2. 非公平锁

非公平锁不像公平锁那样,如果锁被占用时就会排队,并且能保证FIFO,而非公平锁在加锁时,会先进行一次锁的竞争,不管队列中是否有等待线程;

2.1 加锁

final void lock() {
    // 如果进来时,正好有其他线程释放锁,那这里直接加锁,如果成功,则当前线程加锁成功; 第一次非公平
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}
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;
}

对AQS有所了解了再来看ReentrantLock代码是非常简单明了的;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值