当前位置: 首页 > news >正文

【JUC系列】ReentrantLock实现本地锁的源码分析

使用场景

public class ReentrantLockTest {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        new Thread(()->{
            lock.lock();
            // do something
            System.out.println("111");
            try {
                Thread.sleep(Integer.MAX_VALUE);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        }).start();

        new Thread(()->{
            lock.lock();
            // do something
            try {
                Thread.sleep(Integer.MAX_VALUE);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("222");
            lock.unlock();
        }).start();
    }
}

在这里插入图片描述

源码分析

默认使用非公平锁。

    public ReentrantLock() {
        sync = new NonfairSync();
    }

加锁

ReentrantLock#lock加锁,使用sync进行加锁。

public void lock() {
    sync.lock();
}

如果当前的状态为0,则设置exclusiveOwnerThread = thread;,表示当前线程占住当前锁对象。

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

AbstractQueuedSynchronizer#acquire

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

非公平锁的实现,ReentrantLock.NonfairSync#tryAcquire

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

ReentrantLock.Sync#nonfairTryAcquire。当前状态值为0,直接获取锁,如果锁是当前线程占用,则是可重复锁,state++。

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

如果没有获取到锁,在队列中等待,执行AbstractQueuedSynchronizer#addWaiter。末尾节点不为空,设置末尾节点为node的前置节点,node为新的末尾结点。

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

末尾节点为空,执行AbstractQueuedSynchronizer#enq。进行末尾节点的初始化,再插入node节点。

    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

AbstractQueuedSynchronizer#acquireQueued。如果上一个节点是头结点,尝试获取锁。

    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())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire,前置节点可唤醒,返回true,否则设置前置节点的等待状态为-1。

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
        return true;
    if (ws > 0) {
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don't park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

AbstractQueuedSynchronizer#parkAndCheckInterrupt,找到唤醒自己的,进入休眠。

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

解锁

ReentrantLock#unlock

public void unlock() {
    sync.release(1);
}

AbstractQueuedSynchronizer#release。如果成功释放锁,且头节点不为空,waitStatus不为0,执行AbstractQueuedSynchronizer#unparkSuccessor

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

ReentrantLock.Sync#tryRelease,修改state-1,如果state=0,,则释放exclusiveOwnerThread,返回true,否则返回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;
        }

AbstractQueuedSynchronizer#unparkSuccessor。从尾结点找到waitStatus<=0的节点,唤醒

private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
    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);
}

公平锁和非公平锁的不同在于tryAcquire方法。核心在于AbstractQueuedSynchronizer#hasQueuedPredecessors,该方法判断锁同步队列没有多余的节点。

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

总结概括

  1. 加锁的逻辑:
    • 没有锁,state由0变成1,设置exclusiveOwnerThread = thread;
    • 有锁,且拥有锁的线程和加锁线程是同一个,state++;
    • 有锁,但拥有锁的线程和加锁线程不是用一个,队尾添加节点,设置前置节点的waitStatus=-1,进行休眠。
  2. 解锁的逻辑。state–,当state=0,释放锁成功,设置exclusiveOwnerThread = null;,唤醒最后一个waitStatus<=0

相关文章:

  • 五金外贸接单网站/东莞做网站的公司吗
  • 贵阳网站制作公司/百度电脑版官网
  • 搭网站可以用自己电脑做服务器吗/今日新闻摘抄
  • HTML与wordpress兼容/谷歌三件套一键安装
  • 做网站如何防止被黑/朋友圈营销广告
  • 广州网站建设找新际/郑州发布最新通告
  • Swift(2)
  • 与 AI 生成的历史人物聊天是怎样的体验? #Hello History
  • Typora主题定制之数学公式和字体篇
  • 〖百宝书-思维锻炼③〗——三心理论——成功的来源
  • 流程控制|使用循环结构等完成重复性工作(文末附视频)
  • 几种常用的权重初始化方法
  • 反射机制.
  • 【OpenCV】 Octave | 角点检测 | SIFT/SURF算法
  • Vue如何高效通过JSX动态渲染组件
  • 【贪心】AcWing 907. 区间覆盖
  • C++ STL
  • Elasticsearch高级查询—— 查询所有文档