JUC-Lock
- Lock接口:
- Lock接口定义了比同步原语更灵活、更轻巧锁机制;同时,支持多种条件关联锁
- JUC的Lock接口的基本实现为ReentrantLock
- ReentrantLock支持公平、非公平、可重入的互斥同步锁
ReentrantLock
1.ReentrantLock分为两种实现,非公平以及公平模式;
2.公平模式基于CAS+队列实现,而非公平模式则是仅基于CAS实现
3.ReentrantLock中的队列,本质上是基于AQS实现的;而AQS本质上只是一个维持了内存可见的state的双向队列
- ReentrantLock中Node的状态字
//代表当前线程取消竞争锁
static final int CANCELLED = 1;
//代表当前节点正常
static final int SIGNAL = -1;
//代表当前线程在等待条件
static final int CONDITION = -2;
//无法理解.......
static final int PROPAGATE = -3;
//表示状态字;只能用于以上四个状态字以及0
volatile int waitStatus;
- ReentrantLock构造方法
//默认为非公平实现
public ReentrantLock() {
sync = new NonfairSync();
}
//通过传入fair变量控制;
//fair=true,公平锁实现;否则非公平实现
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
- sync是什么?
- Sync是基于AQS实现的ReentrantLock锁同步控制基础
- 如下:
- ReentrantLock#lock()方法
final void lock() {
acquire(1);
}
- ReentrantLock中acquire方法基于AQS
public final void acquire(int arg) {
//至少尝试获取一次锁;
//如果锁没有获取成功,则将当前线程加入等待队列;
//并且中断当前线程
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- ReentrantLock#tryAcquire(int args)
- 尝试获取锁的公平版本
- 非公平版本其实就是略去了公平版本的队列判断:hasQueuedPredecessors()
protected final boolean tryAcquire(int acquires) {
//当前线程ID
final Thread current = Thread.currentThread();
//当前锁状态
int c = getState();
//如果当前锁无人占有
if (c == 0) {
//公平锁讲究先来后到
//如果当前等待队列没有等待线程,
//且通过CAS成功改变锁的状态
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
//设置当前锁持有的线程
setExclusiveOwnerThread(current);
return true;
}
}
//如当前事务请求线程与当前事务执行线程是一样的;可重入锁特性
//这里就是可重入锁特性:同一线程可以重复获取同一把锁
else if (current == getExclusiveOwnerThread()) {
//那么将当前锁持有状态+1
//通过设置acquires=1来完成可重入锁特性
int nextc = c + acquires;
//这里对可重入锁的限制,当同一线程持有锁达到int的上限时;
//会抛出异常
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
//并且重新改变state
setState(nextc);
return true;
}
return false;
}
- ReentrantLock#addWaiter()
- 将当前等待线程以排它模式入队
private Node addWaiter(Node mode) {
//以当前线程建立Node,并且设置Node的模式为排它
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;
//通过CAS修改队尾指针,新增等待线程
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//通过自旋追加节点
enq(node);
return node;
}
- ReentrantLock#acquireQueued()
- 通过自旋不停的获取锁
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//获取p的前置节点
final Node p = node.predecessor();
//如果p的前置节点为head哑节点
//则说明p节点为阻塞队列的对头元素
//在AQS的CLH队列中,只有队头元素才能抢占锁
//且尝试获取锁成功,则返回false
//当返回false时,则说明当前线程不需要挂起
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);
}
}
- ReentrantLock#shouldParkAfterFailedAcquire()
- 检验当前线程是否需要挂起
- 每个线程第一次进入该方法时,都为false;当第二次进入时才为true
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//前驱节点状态字
int ws = pred.waitStatus;
//前驱节点正常;我需要挂起
if (ws == Node.SIGNAL)//-1
return true;
//当状态字大于0,说明前驱节点取消竞争锁;
//此时不停的寻找状态字小于0的节点;
//因为前驱节点的状态字影响了自身的行为;
//自身线程的行为依赖于前驱节点的状态字
if (ws > 0) {//1
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//当一个新的节点进入队列时,默认status为0;
//因此需要将前驱节点的status设置为-1;
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
- ReentrantLock#parkAndCheckInterrupt()
- 挂起当前线程
private final boolean parkAndCheckInterrupt() {
//挂起当前线程
LockSupport.park(this);
return Thread.interrupted();
}
- ReentrantLock#release()
- 释放当前线程,唤醒等待线程
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#tryRelease()
- 尝试释放当前线程
protected final boolean tryRelease(int releases) {
//state表示锁状态;亦是当前线程持有锁的数目
//可重入锁的释放
int c = getState() - releases;
//如果当前线程不是锁的持有者
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果说c==0;则说明当前线程持有的锁已经完全释放
//可重入锁,一个线程可以多次请求同一把锁
if (c == 0) {
free = true;
//设置当前锁的持有线程为null
setExclusiveOwnerThread(null);
}
//修改状态位
setState(c);
return free;
}
- ReentrantLock#unparkSuccessor()
- 唤醒后继线程
private void unparkSuccessor(Node node) {
//head节点的状态
int ws = node.waitStatus;
if (ws < 0)
//修改head节点的状态,以影响后继节点
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
//从后面往前面找,找最接近头节点的小于0的线程
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//如果存在状态位小于0的线程
if (s != null)
//唤醒线程
LockSupport.unpark(s.thread);
}