ReentrantLock lock = new ReentrantLock();
lock.lock();
public void lock() {
sync.lock();
}
//sync.lock(); 分为公平锁和非公平锁(主要区别为:抢锁方式)
//默认为非公平锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
//公平锁
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
//tryAcquire(arg):抢锁成功直接退出,失败则走下面代码
if (!tryAcquire(arg) &&
//addWaiter(Node.EXCLUSIVE):将当前线程添加在双向队列中
//acquireQueued(node, arg):将当前线程挂起一个节点状态为-1的节点后面,
//并且将当前节点的前置状态为1的节点从双向队列中剔除
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//进入下面节点则说明,当前线程是被interrupt()唤醒的,
selfInterrupt();
}
//头尾相等->1、都为null。2、目前只有一个节点
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
//头尾不相等、证明队列还存在其他的节点
return h != t &&
//(s = h.next) == null 如果为true
//说明在生成双向队列的时候,后面的指针指向了前一节点
//而前面的节点指向后面节点的时候没有成功
//s.thread != Thread.currentThread() ture
//头结点的下一个节点是当前节点
((s = h.next) == null || s.thread != Thread.currentThread());
}
//说明有锁的竞争
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
//如果已经有节点了,将当前节点变成尾结点
if (pred != null) {
node.prev = pred;
//如果有并发操作、这一步失败 将进行 下面的 enq(node)
//注意此时只是将当前节点的上一个节点指向了尾节点
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
private Node enq(final Node node) {
for (;;) {
//重新获取尾节点
Node t = tail;
//初始化一个头结点(为了方便操作队列)
if (t == null) {
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
//不管有多少并发、每次只能有一个线程进行操作
//其他的失败后进入死循环添加
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
/**
* node:添加在双向队列中的节点
* arg:1
* */
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)) {
//将当前节点设置为头节点
//释放当前节点中的线程
//将当前节点的上一个节点设置为null
setHead(node);
// help GC
p.next = null;
failed = false;
return interrupted;
}
//shouldParkAfterFailedAcquire(p, node),确保将当前节点一定要挂载一个状态为-1的节点之后
//parkAndCheckInterrupt(), 线程挂起
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//走下面表示线程被interupt唤醒
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//获取当前节点的上一个节点
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
//将当前节点设置为头节点
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
//pred 前置节点
//node 当前节点
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
//前置节点状态为-1、可直接挂起线程
if (ws == Node.SIGNAL)
return true;
//前置节点状态为 1 表示已经取消、则将上一个节点从双向队列中剔除
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//将上一个节点的状态、改为-1
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
//线程挂起
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
//返回当前线程中断标志位
return Thread.interrupted();
}
//将线程中断标志位设置为 true
static void selfInterrupt() {
Thread.currentThread().interrupt();
}