可重入锁

ReentrantLock

1、实现 Lock 接口

public class ReentrantLock implements Lock, java.io.Serializable

2、内部维护 Sync

private final Sync sync;

3、Sync 继承 AbstractQueuedSynchronizer

abstract static class Sync extends AbstractQueuedSynchronizer

4、Sync 的两个实现

(1)公平锁

static final class FairSync extends Sync

(2)非公平锁

static final class NonfairSync extends Sync

(3)默认为非公平锁实现

public ReentrantLock() {
    sync = new NonfairSync();
}

 

NonfairSync 加锁成功

public void lock() {
    sync.lock();
}
final void lock() {
    //没有竞争,CAS将state从0改为1
    if (compareAndSetState(0, 1))
        //exclusiveOwnerThread为当前线程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

 

 

NonfairSync 加锁失败

public void lock() {
    sync.lock();
}
final void lock() {
    //已加锁,CAS修改失败
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        //进入acquire
        acquire(1);
}

public final void acquire(int arg) {
    if (
        //此时state已经是1,tryAcquire结果仍然失败
        !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();
    // 如果还没有获得锁
    if (c == 0) {
        // 尝试用 cas 获得, 这里体现了非公平性: 不去检查 AQS 队列
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 如果已经获得了锁, 线程还是当前线程, 表示发生了锁重入
    else if (current == getExclusiveOwnerThread()) {
        // state++
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    // 获取失败, 回到调用处
    return false;
}
private Node addWaiter(Node mode) {
    // 将当前线程关联到一个 Node 对象上, 模式为独占模式
    Node node = new Node(Thread.currentThread(), mode);
    // 如果 tail 不为 null, cas 尝试将 Node 对象加入 AQS 队列尾部
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            // 双向链表
            pred.next = node;
            return node;
        }
    }
    // 尝试将 Node 加入 AQS
    enq(node);
    return node;
}

1、addWaiter

(1)构造 Node 双向链表

(2)Node 的 waitStatus 状态,其中 0 为默认正常状态,-1 表示需要唤醒其后继节点

(3)Node 创建为懒惰初始化

(4)首次创建链表时:第一个 Node 为 Dummy(哑元)或哨兵,用来占位,并不关联线程,第二个 Node 关联当前线程

(5)双向链表的末尾 Node,其 waitStatus 总为 0

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) {
            // 还没有, 设置 head 为哨兵节点(不对应线程,状态为 0)
            if (compareAndSetHead(new Node())) {
                tail = head;
            }
        } else {
            // cas 尝试将 Node 对象加入 AQS 队列尾部
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

2、第一轮循环

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //获取当前Node的前驱节点p
            final Node p = node.predecessor();
            //若p为头节点,即node为队列的第二位,则再次tryAcquire获取锁,此时state为1,仍失败
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (
                //第一次shouldParkAfterFailedAcquire:将前驱节点,即head的waitStatus改为-1,若返回false,进入第二轮循环,继续竞争
                shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    // 获取上一个节点的状态
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL) {
        // 上一个节点都在阻塞, 则自己也阻塞
        return true;
    }
    // > 0 表示取消状态
    if (ws > 0) {
        // 上一个节点取消, 那么重构删除前面所有取消的节点, 返回到外层循环重试
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        // 这次还没有阻塞
        // 但下次如果重试不成功, 则需要阻塞,这时需要设置上一个节点状态为 Node.SIGNAL
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

3、第二轮循环

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //获取当前Node的前驱节点p
            final Node p = node.predecessor();
            //若p为头节点,即node为队列的第二位,则再次tryAcquire获取锁,此时state为1,仍失败
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (
                //第二次shouldParkAfterFailedAcquire:前驱Node的waitStatus已经是-1,若返回true,则进入阻塞
                shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

4、是否需要 unpark,由当前节点的前驱节点,是否 waitStatus == Node.SIGNAL 决定,而不是本节点的 waitStatus 决定

private final boolean parkAndCheckInterrupt() {
    //调用park阻塞当前线程
    LockSupport.park(this);
    return Thread.interrupted();
}

 

4、多个线程经竞争失败

 

 

NonfairSync 释放锁成功

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    //尝试释放锁
    if (tryRelease(arg)) {
        //队列头节点
        Node h = head;
        if (
            //队列不为 null
            h != null &&
            //waitStatus == Node.SIGNAL 才需要 unpark
            h.waitStatus != 0)
            // unpark AQS 中等待的线程
            unparkSuccessor(h);
        return true;
    }
    return false;
}

1、公平锁、非公平锁,释放锁都是相同的 tryRelease 实现

protected final boolean tryRelease(int releases) {
    // state--
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 支持锁重入, 只有 state 减为 0, 才释放成功
    if (c == 0) {
        free = true;
        //exclusiveOwnerThread设置为null,表示没有线程占用锁
        setExclusiveOwnerThread(null);
    }
    //state设置为0,表示释放锁
    setState(c);
    return free;
}

2、setExclusiveOwnerThread、setState 先后次序

(1)state 为 volatile

private volatile int state;

(2)exclusiveOwnerThread 并非 volatile

private transient Thread exclusiveOwnerThread;

(3)setState 后会加入写屏障,保证在写屏障之前,setExclusiveOwnerThread 的改动,都同步到主存当中,对其他线程可见

private void unparkSuccessor(Node node) {
    //获取node的waitStatus
    int ws = node.waitStatus;
    // 如果状态为 Node.SIGNAL,尝试重置状态为 0
    if (ws < 0) {
        //允许失败
        compareAndSetWaitStatus(node, ws, 0);
    }
    // 找到需要 unpark 的节点, 但本节点从 AQS 队列中脱离, 是由唤醒节点完成的
    Node s = node.next;
    // 不考虑已取消的节点, 从 AQS 队列从后至前找到队列最前面需要 unpark 的节点
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

3、unparkSuccessor

(1)找到队列中,离 head 最近的一个、没取消的 Node,unpark 恢复其运行

(2)其 Node 关联的线程,在 acquire -> acquireQueued -> parkAndCheckInterrupt -> LockSupport.park 被唤醒,返回

private final boolean parkAndCheckInterrupt() {
    //线程在此被阻塞
    LockSupport.park(this);
    //被park的线程,需要interrupted,返回打断标记(true),并清除打断标记,即设置为false
    return Thread.interrupted();
}
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //获取node的前驱节点
            final Node p = node.predecessor();
            //p为head,node尝试获取锁,state为0,成功
            if (p == head && tryAcquire(arg)) {
                //将新head设置为node
                setHead(node);
                //原head的next指针设置为null,即与node断开关联
                p.next = null; // help GC,原head因为从链表断开,而可被垃圾回收
                failed = false;
                //返回true
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                //parkAndCheckInterrupt返回true,进入if块
                parkAndCheckInterrupt())
                //interrupted设置为true,进入下一轮循环
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
private void setHead(Node node) {
    //将head设置为node
    head = node;
    //断开node与线程关联
    node.thread = null;
    //node的prev指针设置为null,即与原head断开关联
    node.prev = null;
}

 

NonfairSync 释放锁失败

1、此时,有其它线程竞争(该线程不在阻塞队列),且被其先占用 exclusiveOwnerThread

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //获取node的前驱节点
            final Node p = node.predecessor();
            //p为head,node尝试获取锁,state为-1,tryAcquire失败
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null;
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                //parkAndCheckInterrupt返回true,进入if块
                parkAndCheckInterrupt())
                //interrupted设置为true,进入下一轮循环
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

2、重新进入 shouldParkAfterFailedAcquire、parkAndCheckInterrupt,被阻塞

 

NonfairSync 可重入原理

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}
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();
    //如果还没有获得锁
    if (c == 0) {
        //尝试使用CAS获得锁,体现非公平性: 不检查AQS队列
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //如果已经获得了锁, 线程还是当前线程, 表示发生了锁重入
    else if (current == getExclusiveOwnerThread()) {
        // state++
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}
protected final boolean tryRelease(int releases) {
    // state-- 
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 支持锁重入, 只有 state 减为 0, 才释放成功
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

 

ReentrantLock 可打断原理

1、不可打断模式:即使它被打断,仍会驻留在 AQS 队列中,一直要等到获得锁后,才能继续运行,只是打断标记设置为 true

private final boolean parkAndCheckInterrupt() {
    // 如果打断标记已经是 true, 则 park 会失效
    LockSupport.park(this);
    // interrupted 会清除打断标记
    return Thread.interrupted();
}
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;
                failed = false;
                // 还是需要获得锁后, 才能返回打断状态
                return interrupted;
            }
            if (
                shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt()
            ) {
                // 如果是因为 interrupt 被唤醒, 返回打断状态为 true
                interrupted = true;
            }
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
public final void acquire(int arg) {
    if (
        !tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
    ) {
        // 如果打断状态为 true
        selfInterrupt();
    }
}
static void selfInterrupt() {
    // 重新产生一次中断
    Thread.currentThread().interrupt();
}

2、可打断模式

public final void acquireInterruptibly(int arg) throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    // 如果没有获得到锁,进入doAcquireInterruptibly
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}
//可打断的获取锁流程
private void doAcquireInterruptibly(int arg) throws InterruptedException {
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt()) {
                //在 park 过程中如果被 interrupt,此时抛出异常,而不会再次进入 for (;;)
                throw new InterruptedException();
            }
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

 

FairSync 实现原理

final void lock() {
    acquire(1);
}
public final void acquire(int arg) {
    if (
        !tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
    ) {
        selfInterrupt();
    }
}
// 与非公平锁主要区别在于 tryAcquire 方法的实现
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (
            // 先检查 AQS 队列中是否有前驱节点, 没有才去竞争
            !hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            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;
}
public final boolean hasQueuedPredecessors() {
    Node t = tail;
    Node h = head;
    Node s;
    return
        // h != t 时,表示队列中有 Node
        h != t &&
        (
        // (s = h.next) == null,表示队列中只有一个Node,即不与线程关联的head
        (s = h.next) == null ||
        // 或队列中第二个Node,所关联的线程不是当前线程
        s.thread != Thread.currentThread()
    );
}

 

条件变量实现原理

1、每个条件变量,对应着一个等待队列,其实现类为 ConditionObject

2、await 流程

public final void await() throws InterruptedException {
    //如果线程已经被标记为中断,则抛出异常
    if (Thread.interrupted())
        throw new InterruptedException();
    //创建新Node到条件变量的等待队列(单向链表)
    Node node = addConditionWaiter();
    //释放锁,该线程在阻塞队列(双向链表)中的节点也已经被移除
    //持有锁的线程可能发生锁重入,需要完全释放锁
    long savedState = fullyRelease(node);
    //这里会将线程挂起,除非线程节点被移到AQS的阻塞队列,或是线程被外部中断
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        //调用park,在条件变量队列阻塞
        LockSupport.park(this);
        //检查是否是由于被中断而唤醒,如果是,则跳出循环
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    //在阻塞队列中尝试获取锁
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    //节点已经在AQS阻塞队列中,与Condition的等待队列联系断开
    //对于SIGNAL唤醒的线程而言,SIGNAL时除了将节点移到阻塞队列,同时也清空了node.nextWaiter
    //而对于中断唤醒的线程而言,只是将节点移到阻塞队列,并没有清空node.nextWaiter(因为此时线程不持有锁,操作等待线程并非线程安全)
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    //根据interruptMode决定是否需要抛出异常
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}
private Node addConditionWaiter() {
    Node t = lastWaiter;
    //删除队列链表中,所有已取消的Node
    if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        t = lastWaiter;
    }
    //创建一个关联当前线程的新Node,状态为-2,添加至队列尾部
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    lastWaiter = node;
    return node;
}

final long fullyRelease(Node node) {
    boolean failed = true;
    try {
        //获取state计数值
        long savedState = getState();
        //清空state
        if (release(savedState)) {
            failed = false;
            //返回0
            return savedState;
        } else {
            throw new IllegalMonitorStateException();
        }
    } finally {
        if (failed)
            node.waitStatus = Node.CANCELLED;
    }
}

public final boolean release(long arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            //唤醒后继节点,进行竞争
            unparkSuccessor(h);
        return true;
    }
    return false;
}

3、signal 流程

public final void signal() {
    //检查调用signal的线程,是否为锁的持有者
    if (!isHeldExclusively())
        //非锁的持有者,则抛出异常
        throw new IllegalMonitorStateException();
    //获取条件变量的第一个Node
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}

private void doSignal(Node first) {
    do {
        //断开first与条件变量的关联
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (
        //将一个节点从条件队列,转移到AQS队列。如果成功返回true
        //可能的失败原因:被打断、超时等,从而放弃对锁的竞争
        !transferForSignal(first) &&
        //若失败,获取条件变量的下一个Node,进入下一轮唤醒循环
        (first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
    //尝试将被唤醒线程的Node,state从-2改为0
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        //修改失败,说明该节点已被取消,则寻找条件变量下一个节点
        return false; 
    //修改成功,将node加入到AQS队列末尾,成功返回node的前驱节点p
    Node p = enq(node);
    //获取p的waitStatus
    int ws = p.waitStatus;
    if (
        //表示p被取消
        ws > 0 ||
        //因为双向链表末尾Node的waitStatus必定为0,所以需要将其改为-1
        !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        //p被取消,或修改p失败,则直接唤醒node
        LockSupport.unpark(node.thread);
    return true;
}
posted @   半条咸鱼  阅读(163)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示