ReentrantLock锁底层原理(加锁、解锁、可打断模式、公平锁、条件变量等源码)

本文详细探讨了ReentrantLock的底层实现,包括加锁过程中的lock()、acquire()及其相关方法,解锁操作如unlock()、release(),以及可打断模式和公平锁的实现。在加锁环节,分析了如何通过tryAcquire()和enq()将线程加入等待队列。解锁时,讲解了unparkSuccessor()如何唤醒后续线程。此外,还介绍了条件变量的实现原理。
摘要由CSDN通过智能技术生成

类结构

在这里插入图片描述

static final class NonfairSync extends Sync {
   
}

一、加锁

1、lock()

final void lock() {
   
	//先尝试直接加锁
    if (compareAndSetState(0, 1))
    	//成功了就结束方法
        setExclusiveOwnerThread(Thread.currentThread());
    else
    	//失败了调用acquire(1)
        acquire(1);
}

2、acquire(int arg)

public final void acquire(int arg) {
   
	//再次尝试加锁,加锁失败将该线程加入AQS队列。
	//这两个操作进行完之后,将该线程打断,让出时间片
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

3、tryAcquire(int acquires)

protected final boolean tryAcquire(int acquires) {
   
	//调用不公平的acquire
    return nonfairTryAcquire(acquires);
}

4、nonfairTryAcquire(int acquires)

final boolean nonfairTryAcquire(int acquires) {
   
	//获取当前线程和当前锁的owner的状态
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
   
    	//如果没有加锁,就加锁
    	//这里体现了不公平性:外来线程可以直接加锁,不用先去检查AQS队列
        if (compareAndSetState(0, acquires)) {
   
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //如果加了锁并且锁的owner就为当前线程时,状态值+1(表示锁重入)
    else if (current == getExclusiveOwnerThread()) {
   
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    //否则返回false。表示线程竞争锁失败。接着调用acquireQueued、addWaiter将其加入AQS队列
    return false;
}

5、addWaiter(Node mode)

其中,headtail都可以看作指向Dummy的指针。

private Node addWaiter(Node mode) {
   
	//将当前线程关联到一个模式为独占模式的Node对象上
    Node node = new Node(Thread.currentThread(), mode);
    //如果 tail 不为 null, cas 尝试将 Node 对象加入 AQS 队列尾部
    Node pred = tail;
    if (pred != null) {
   
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
   
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

6、enq(final Node node)

private Node enq(final Node node) {
   
    for (;;) {
   
        Node t = tail;
        if (t == null) {
   
        	//此时head = tail = null,说明队列中还没有元素
        	//将tail和head都从null->dummy 
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
   
            node.prev = t;
            //将node对象加入AQS队列尾部,将tail从t设置成node
            if (compareAndSetTail(t, node)) {
   
                t.next = node;
                return t;
            }
        }
    }
}

7、acquireQueued(final Node node, int arg)

node结点上关联的是当前线程(和锁的owner不同),arg一般是1,表示加锁的值。
线程在这个方法里,会死循环不断尝试获得锁,失败两次后进入park阻塞。

final boolean acquireQueued(final Node node, int arg) {
   
    boolean failed = true;
    try {
   
        boolean interrupted = false;
        for (;;) {
   
        	//在这个死循环中,
            final Node p = node.predecessor();
            /*
            获取当前线程的前驱线程
            若前驱==head,说明当前线程就为AQS队列中的第一个线程ÿ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值