简单查看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,期望修改值 1
if (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
// 判断是否满足cas
if (compareAndSetTail(pred, node)) {
// 将 ThreadB 的 next 指向 ThreadC
pred.next = node;
// 返回当前 node 节点
return node;
}
自旋的方式把尾节点对准 AQS队列中最后的 ThreadC 节点
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;
}
}
}
}
// 获取尾节点
Node t = tail;
// 如果尾节点是空
if (t == null) {
// 通过 cas 判断条件是否满足
if (compareAndSetHead(new Node()))
//
tail = head;
}
在尾节点不为空的情况下,把 tall 节点
if (t == null) { // Must initialize
if (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 GC
failed = 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 GC
failed = false;
return interrupted;
}
如果线程再次抢锁失败,那么头节点开始尝试获取锁
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
如果获取到了头节点,先阻塞线程,然后获取中断状态,LockSupport.park(this);最后调用了native的方法
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}