ReentrantLock 基于源码了解工作流程

ReentrantLock和synchronized在jdk1.8版本后性能相差无几,甚至synchronized小优,但是synchronized不支持中断和超时,也就是说通过synchronized一旦被阻塞住,如果一直无法获取到所资源就会一直被阻塞,即使中断也没用,这对并发系统的性能影响太大了;Lock支持中断和超时、还支持尝试机制获取锁,对synchronized进行了很好的扩展,所以从灵活性上Lock是明显优于synchronized的

基本方法
// 构造方法
// boolean fair 是否为公平锁
ReentrantLock(boolean fair)

// 尝试拿锁,拿不到阻塞等待
void lock();
// 释放锁
void unlock();
// 等待拿锁的时间可被中断
void lockInterruptibly() throws InterruptedException; 
// 尝试拿锁,不等待
boolean tryLock();
// 尝试拿锁,等待timeout时间
boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException;
公平锁
拿锁
final void lock() {
    acquire(1);
}

public final void acquire(int arg) {
    // 首先尝试拿锁
    if (!tryAcquire(arg) &&
        // addWaiter 拿锁失败时候 加入(创建)请求队列
        // acquireQueued 在一个死循环中 判断是否是队列头 并尝试拿锁,否则阻塞 LockSupport.park(this)
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
//尝试拿锁
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) { 
        // 当前锁状态为空闲
        // hasQueuedPredecessors 当前线程是否需要排队(公平锁) true: 需要, false: 不需要
        if (!hasQueuedPredecessors() &&
            // 通过 CAS 拿锁
            compareAndSetState(0, acquires)) {
            // 成功拿到锁之后设置当前持有锁的线程为当前线程
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 当前有线程持有锁
    // 判断当前持有锁的线程是否是当前线程
    else if (current == getExclusiveOwnerThread()) {
        // 是当前线程 则 c + 1 (可重入)
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc); // 设置当前锁状态
        return true;
    }
    return false;
}

// 将当前线程加入请求队列
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    // 判断当前请求队列是否存在
    if (pred != null) {
        // 队列存在 则直接加入队尾
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    // 队列不存在 创建队列 并 将当前请求放入队列
    enq(node);
    return node;
}
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        // 死循环
        for (;;) { 
            // 拿到当前线程的prev
            final Node p = node.predecessor();
            // 若 prev 是头部 则尝试拿锁
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            // 判断当前线程请求状态是否应该 park
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt()) // 阻塞 LockSupport.park(this);
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
释放锁
public final boolean release(int arg) {
    // 释放锁
    if (tryRelease(arg)) {
        Node h = head;
        // 释放成功后 将请求队列的 head 节点 unpark 唤醒
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
protected final boolean tryRelease(int releases) {
    // 锁定次数 - 1
    int c = getState() - releases;
    // 判断当前线程是否是当前持有锁的线程
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 如果 c == 0 则 当前锁为空闲状态
    if (c == 0) {
        free = true;
        // 设置持有锁的线程为空
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}
非公平锁
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值