ReentrantLock&AQS源码分析

本文详细解析了ReentrantLock的工作原理,包括其可中断、可超时、公平锁与非公平锁特性。通过分析加锁、解锁流程,展示了AQS(AbstractQueuedSynchronizer)队列在锁管理中的作用,以及如何通过tryAcquire和tryRelease方法实现锁的获取与释放。同时,讨论了公平锁如何确保线程按FIFO顺序获取锁,以及锁超时和中断策略。
摘要由CSDN通过智能技术生成

1、ReentrantLock的几个特点

  • 可中断
  • 可以设置超时时间
  • 可以设置为公平锁
  • 支持多个条件变量
  • 与 synchronized 一样,都支持可重入

2、AQS原理

AQS内部主要维护了一个双向队列和一个状态state
在独占模式中,双向队列存储了所有阻塞的节点(当然也有被取消的节点)

节点存储了当前线程,每个节点也有几个状态,其中

  • 1表示节点被取消
  • -1表示该节点后面的节点需要被唤醒
  • -2表示节点在条件变量中

AQS中的state变量的几个状态

  • 0表示无锁
  • 1表示有锁
  • 大于1表示可重入锁

3、ReentrantLock的加锁流程

先看大概的加锁流程,以独占式不可中断锁为例。

final void lock() {
    //cas尝试获取锁
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    //获取锁失败,则进入下面acquire
    else
        acquire(1);
}

//以独占模式获取,忽略中断
public final void acquire(int arg) {
	//再一次尝试获取锁
    if (!tryAcquire(arg) &&		//下面第一个方法
        //获取锁失败则加入到队列中,并阻塞等待,直到获取到锁
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))		//下面方法(2)(3)
        //如果途中被中断,则设置线程为中断状态,因为之前线程被中断后又取消了中断标记。
        selfInterrupt();
}

tryAcquire(arg)->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;
}


//(2)将线程节点添加到AQS中阻塞队列的尾节点后面
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    //添加失败,则在循环中重试,直到添加成功
    enq(node);	//下面第一个方法
    return node;
}

//将线程节点添加到AQS中阻塞队列的尾节点后面
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { //保证有一个头节点,该节点不存储任何线程,相当于哨兵
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}


//(3)在阻塞队列中一直阻塞,直到获取到锁
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            //当前节点的前一个节点是头节点,尝试去获取锁
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //不是头节点判断是否应该阻塞
            if (shouldParkAfterFailedAcquire(p, node) &&
                //阻塞线程
                parkAndCheckInterrupt())	//下面方法(4)
                //即使被中断,也只是改变中断状态,仍然在循环中再次尝试获取锁
                interrupted = true;
        }
    } finally {
    	//取消节点,比如被中断或者调用tryLock(time),在一定时间内没获取到锁则直接退出,不再竞争锁
        if (failed)
      		//将当前线程节点从阻塞队列中移除
            cancelAcquire(node);
    }
}


//取消节点,比如被中断或者调用tryLock(time)
private void cancelAcquire(Node node) {
    if (node == null)
        return;
    node.thread = null;

    Node pred = node.prev;
    while (pred.waitStatus > 0)
        node.prev = pred = pred.prev;

    Node predNext = pred.next;

    //修改状态
    node.waitStatus = Node.CANCELLED;

    //如果该节点是尾节点则将前一个节点设置为尾节点
    if (node == tail && compareAndSetTail(node, pred)) {
        compareAndSetNext(pred, predNext, null);
    } else {
        
        int ws;
        //前驱节点不是头节点
        if (pred != head &&
        	//并且前驱节点没有被取消
            ((ws = pred.waitStatus) == Node.SIGNAL ||
             (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
            pred.thread != null) {
            //将该节点从阻塞队列中删除
            Node next = node.next;
            if (next != null && next.waitStatus <= 0)
                compareAndSetNext(pred, predNext, next);
        	
        } else {
            //如果是前驱节点是头节点,唤醒后面的节点
            unparkSuccessor(node);
        }

        node.next = node; // help GC
    }
}

/*(4)检查和更新未能获取锁的节点的状态。 如果线程应该阻塞,则返回 true。这里需要理Node
中waitStatus的几种状态。在独占模式中,1表示线程已经被取消,-1(SIGNAL)表示后继线程需
要unpark,创建的新节点默认为0。*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        return true;
        
     //表示该节点已经被取消,需要删除节点
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
     //这里Node.SIGNAL表示要唤醒后继的线程的标识
    } else {
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

4、ReentrantLock的解锁流程

public final boolean release(int arg) {
	//解锁
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);			//唤醒后面的节点,下面的方法(1)
        return true;
    }
    return false;
}

//释放锁,修改状态
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;
}


//(1)唤醒后面的节点
private void unparkSuccessor(Node node) {

    // 如果状态为 Node.SIGNAL 尝试重置状态为 0
 	// 不成功也可以
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    //找到需要unpark的节点
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

5、锁超时

//以独占定时模式获取锁
private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
    if (nanosTimeout <= 0L)
        return false;
    final long deadline = System.nanoTime() + nanosTimeout;
    //加入到阻塞队列中
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return true;
            }
            nanosTimeout = deadline - System.nanoTime();
            if (nanosTimeout <= 0L)
                return false;
            if (shouldParkAfterFailedAcquire(p, node) &&
                nanosTimeout > spinForTimeoutThreshold)
                //与上面acquireQueued方法类似,只是指定了阻塞时间
                LockSupport.parkNanos(this, nanosTimeout);
            if (Thread.interrupted())
                throw new InterruptedException();
        }
    } finally {
        //被打断或者时间到了则取消节点
        if (failed)
            cancelAcquire(node);
    }
}

6、锁可中断

//以独占模式获取,如果中断则中止
public final void acquireInterruptibly(int arg)
    throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

private void doAcquireInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                //中断后直接抛异常。可以类比acquireQueued方法,acquireQueued方法中只是改变中断状态
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

7、公平锁&非公平锁

//NonfairSync非公平锁的的实现
final void lock() {
    //每次lock会尝试去获取锁
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

public final void acquire(int arg) {
	//尝试获取锁
    if (!tryAcquire(arg) &&
    	//添加到AQS队列中阻塞
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
//tryAcquire->nonfairTryAcquire
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;
}

//FairSync非公平锁
final void lock() {
    acquire(1);
}

//acquire->tryAcquire
//非公平锁的tryAcquire
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;
}


8、可重入

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()) {
        //将state加1
        int nextc = c + acquires;
        if (nextc < 0)
            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、付费专栏及课程。

余额充值