前言
- 在高并发领域,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调用内部类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; }