前言

  • 在高并发领域,ReentrantLock有着广泛的用处,防止多线程带来的并发问题
  • 对于源码,很多人和我一开始一样都觉得非常神秘
  • 这次我将对ReentrantLock进行全方面的揭秘

核心

  • AbstractQueuedSynchronizer
    • AQS是JDK实现的CAS同步器。里面的核心是state和两个node
    • state标识同步器现在的状态,node作为队列串联同步器中的节点
    • 使用volatile保证参数的可见性
volatile Node prev;
volatile Node next;
private volatile int state;

整体结构

  • ReentrantLock 调用内部类Sync,Sync继承AbstractQueuedSynchronizer

整体流程

  • 死磕源码系列(ReentrantLock)-LMLPHP
  • ReentrantLock调用内部类Sync的acquire方法,底层走的是AbstractQueuedSynchronizer,AbstractQueuedSynchronizer会尝试获取锁,获取失败之后会加入队列中,然后节点自旋去获取锁,一旦成功就将自己的节点至于头部,然后退出。
  • cas实现(compareAndSet)。jdk9之前使用的是unsafe,jsk9之后使用的是varHandler。

核心代码

AQS:

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
  • tryAcquire是第一次尝试获取所,公平锁和非公平锁的区别只是判断自己节点是否除了head节点外还是在自己前面的,校验的是公平锁,不校验的是非公平锁
  • addWaiter是节点加入到队列中
  • 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);
        }
    }

释放锁

       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;
        }
01-18 16:04