简单查看ReentrantLock使用方式,ReentrantLock的无参构造是创建一个非公平锁
非公平锁的 lock 实现原理,首先通过 cas 检查是否获取到锁,获取到锁就将线程放到AbstractOwnableSynchronizer对象中,没获取到的话,在尝试获取锁,获取成功返回, 获取失败先把当前线程创建成Node节点,然后添加到AQS队列中,在尝试获取锁,获取成功设置状态返回,获取失败,当前线程不在操作,头节点开始获取锁。非公平锁主要是在插入AQS队列时候尝试获取锁,加入AQS队列后的获取锁方式依然是FIFO。
static Lock lock = new ReentrantLock();public static void main(String[] args) {// 加锁lock.lock();// 释放锁lock.unlock();}
查看非公平锁的实现,非公平锁继承了Sync。
static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L;/*** 加锁方法*/final void lock() {// cas操作,操作成功修改即获得到锁 预期值0,期望修改值 1if (compareAndSetState(0, 1))//把当前线程赋值到 已获取锁的对象中setExclusiveOwnerThread(Thread.currentThread());else// 再次获取获取锁acquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}
public final void acquire(int arg) {// tryAcquire(1) 尝试获取锁 成功获取锁返回true,没获取到false// 如果获取锁成功 不执行任何逻辑// 如果获取锁失败 :// 先执行 addWaiter(Node.EXCLUSIVE)// 在执行 acquireQueued()if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
addWaiter() 主要负责创建一个node节点,并添加到AQS队列中
private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// 下图表明Node pred = tail;if (pred != null) {node.prev = pred;// 尝试把当前node 加入到尾节点if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}//enq(node);return node;}
// 创建了 ThreadC 的 Node 节点
Node node = new Node(Thread.currentThread(), mode);
// 获取尾节点,也就是 ThreadB线程
Node pred = tail;
// 如果尾节点不是null
if (pred != null) {
// 把当前节点加在尾节点之后
node.prev = pred;
现在 是 ThreadC 的 perv 指向了 ThreadB,但是 ThreadB 的next 还未指向 ThreadC
// 判断是否满足casif (compareAndSetTail(pred, node)) {// 将 ThreadB 的 next 指向 ThreadCpred.next = node;// 返回当前 node 节点return node;}
自旋的方式把尾节点对准 AQS队列中最后的 ThreadC 节点
private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}
// 获取尾节点Node t = tail;// 如果尾节点是空if (t == null) {// 通过 cas 判断条件是否满足if (compareAndSetHead(new Node()))//tail = head;}
在尾节点不为空的情况下,把 tall 节点
if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}
acquireQueued 负责把当前节点插入到AQS队列
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 GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}
插入AQS队列时会再次尝试获取锁,获取成功,直接返回
if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}
如果线程再次抢锁失败,那么头节点开始尝试获取锁
if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}
如果获取到了头节点,先阻塞线程,然后获取中断状态,LockSupport.park(this);最后调用了native的方法
private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();}