lock方法#

当ReentrantLock类的实例对象尝试获取锁的时候,调用lock方法,

image

会进入sync的lock方法,其中Sync是ReentrantLock的一个内部类,ReentrantLock构造方法会默认使用非公平锁NonfairSync,这个类是继承于Sync的

        final void lock() {
            if (!initialTryLock())
                acquire(1);
        }
// 其中Sync的initialTryLock是抽象方法,需要看非公平锁实现方法

[!TIP]
在这里是第一次尝试获取锁

由于ReentrantLock是个可重入锁,判断里有重入的判断

final boolean initialTryLock() {
            Thread current = Thread.currentThread();
			// 获取当前线程的对象
            if (compareAndSetState(0, 1)) { // first attempt is unguarded
			// 用CAS比较state状态是否为0(无人持有锁),如果是,就转为1(获取到锁)
                setExclusiveOwnerThread(current);
			// 将当前进程设置为拥有锁的线程
                return true;
            } else if (getExclusiveOwnerThread() == current) {
			// 当前线程为拥有锁的线程(重复获取),重入
                int c = getState() + 1;
                if (c < 0) // overflow
			// 负数,state是个int类型数据,超出可能导致溢出变为负数
                    throw new Error("Maximum lock count exceeded");
                setState(c);
			// 设置新的state
                return true;
            } else
			// 已有线程占锁,返回为false
                return false;
        }

然后开始调用acquire方法,传入1

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

调用tryAcquire()方法,其中tryAcquire()方法是一个只有抛出异常的方法,需要重写,我们看非公平锁的写法

[!TIP]
这是第二次获取锁

        protected final boolean tryAcquire(int acquires) {
            if (getState() == 0 && !hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

这里,如果state是0,即没有线程占用锁的情况下getState() == 0​这个为真!hasQueuedPredecessors()执行这个方法,这个方法会检查是否已经出现了等待队列

    public final boolean hasQueuedPredecessors() {
        Thread first = null; Node h, s;
        if ((h = head) != null && ((s = h.next) == null ||
                                   (first = s.waiter) == null ||
                                   s.prev == null))
            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
        return first != null && first != Thread.currentThread();
    }

当未出现 同步队列/阻塞队列 ,或者当前线程是队列的第一个时,执行compareAndSetState(0, acquires),第二次尝试获取锁,如果成功,返回真

否则返回假,执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

    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;
    }

Node是双向队列:阻塞队列一个节点,是为了保证原子化所以包装起来的

如果tail尾指针指向的节点不为空,则设置新生成的为尾指针指向的

否则(阻塞队列为空),调用enq函数

    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
			// 使用CAS,防止多线程同时创建头节点,所以本质上还是需要抢入队顺序
                    tail = head;
			// 初始化头节点,并将尾指针指向头节点
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
			// 判断t是否为尾节点,如果有线程更快的改掉尾节点,那么修改失败,
			// 重新进入for循环
                    t.next = node;
                    return t;
			// 修改成功
                }
            }
        }
    }

[!TIP]
这是第三次尝试获取锁

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
			// 获取node的前一个节点,如果前一个节点是头节点(当前节点是第一个)
			// 执行tryAcquire(arg),执行第三次尝试获取锁
                if (p == head && tryAcquire(arg)) {
			// 获取锁成功,出队
                    setHead(node);// 将node设为头节点
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

如果第三次尝试获取锁失败了,会调用shouldParkAfterFailedAcquire()方法,将node的前一个节点传入(node一直都是加入的节

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐