ReetrantLock分为公平锁和非公平锁
public static void main(String[] args) {
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
}
非公平枪锁机制
public ReentrantLock() { // ReentrantLock默认是创建非公平锁
sync = new NonfairSync();
}
// lock.lock();
public void lock() {
sync.lock();
}
final void lock() {
if (compareAndSetState(0, 1)) // 非公平锁上来就强行获取锁一次
setExclusiveOwnerThread(Thread.currentThread()); // 抢锁成功着修改lock锁占用的线程
else
acquire(1);
}
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
// 加入队列并进行自旋等待
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 再次抢锁,并且判断占用锁资源的线程是否是当前线程
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {// 再次抢锁
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // 获取lock状态
if (c == 0) { // 如果等于0表示无锁状态
if (compareAndSetState(0, acquires)) { // 再次枪锁
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 判断当前占用锁线程是否是当前线程,如果是就重入锁
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
// 加入队列并进行自旋等待
// acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 添加一个互斥锁的节点
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); // 当前线程创建node
// Try the fast path of enq; backup to full enq on failure
Node pred = tail; //尾节点
if (pred != null) { // 尾节点不为空并且假设不存在竞争的情况修改
node.prev = pred; // 当前node节点prev指向上一个节点
if (compareAndSetTail(pred, node)) { //cas 比较修改尾节点指向当前节点
pred.next = node; //上一个节点的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; // 当前node节点prev指向上一个节点
if (compareAndSetTail(t, node)) { //比较修改尾节点指向当前节点
t.next = node; // 上一个节点的next下个节点指向当前node节点
return t;
}
}
}
}
图1
公平锁枪锁机制
public ReentrantLock(boolean fair) { // Lock lock = new ReentrantLock(true); 创建对象传true
sync = fair ? new FairSync() : new NonfairSync();
}
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 抢锁
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { // 无锁状态
if (!hasQueuedPredecessors() && // 校验队列当中是否有其他线程等待
compareAndSetState(0, acquires)) { // CAS(#Lock) -> 原子操作| 实现互斥的判断
setExclusiveOwnerThread(current); // 修改lock为当前线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 判断当前占用锁资源线程和当前抢锁线程是同一个,如果是就重入锁
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);// 重入次数添加
return true;
}
return false; // false表示抢锁失败
}
}
// 加入队列并进行自旋等待
// acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 添加一个互斥锁的节点
private Node addWaiter(Node mode) { //非公平锁和公平锁添加队列都是同一个
Node node = new Node(Thread.currentThread(), mode); // 当前线程创建node
// Try the fast path of enq; backup to full enq on failure
Node pred = tail; //尾节点
if (pred != null) { // 尾节点不为空并且假设不存在竞争的情况修改
node.prev = pred; // 当前线程node的上一个指向tail尾节点
if (compareAndSetTail(pred, node)) { //cas 比较两个节点指向修改成功
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;
}
}
}
}
公平锁和非公平锁排队阻塞
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); // 抢锁成功抛弃空node节点,从新指向,
p.next = null; // help GC
failed = false;
return interrupted;
}
// 否则,让线程去阻塞(park)
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) // 在循环第二次shouldParkAfterFailedAcquire(p, node)方法后会返回true执行这段代码,阻塞
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
// 修改当前node的waitStatus状态
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; // The field is initialized to 0 for normal sync nodes常的同步节点,该字段被初始化为0
if (ws == Node.SIGNAL)// waitStatus value to indicate successor's thread needs unparking 当前状态如果为-1 值表示后继线程需要唤醒
return true;
if (ws > 0) {// waitStatus value to indicate thread has cancelled 大于0 值表示线程已经取消
do {
node.prev = pred = pred.prev; // 表示当前node节点前后指向改变
} while (pred.waitStatus > 0); // 查看图2
pred.next = node;
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL); // 修改当前node状态为Node.SIGNAL -1
}
return false;
}
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this); // 被中断唤醒
return Thread.interrupted(); // 表示中断状态(是否是中断唤醒的)
}
// 抢锁成功后的节点指向
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
图2
图3
公平锁和非公平锁释放锁资源
// lock.unlock();
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0) // 如果队列中头节点不为空,并且当前node节点waitStatus状态不为默认值0
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) { //释放锁只有一个线程释放
int c = getState() - releases; // 扣减重入次数
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) { // 如果为0着清除 Thread当前状态为null
free = true;
setExclusiveOwnerThread(null);
}
setState(c); // 修改锁为占用
return free;
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0) //当前node的waitStatus如果为-1表示需要修改为0
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) { // 如果当前node的下一个节点为空或者是需要抛弃的节点着进入其中修改
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0) // 查询到小于等于0的那个节点,就是队列当中第一个线程A
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);// 当前node节点唤醒
}