ReentrantLock 公平锁与非公平锁 加锁与释放锁 源码

公平锁

final void lock() {
    acquire(1);
}

public final void acquire(int arg) {
    // 尝试获取锁 获取成功 直接结束
    // mode 指示节点正在以独占模式等待的标记 static final Node EXCLUSIVE = null;
    // 如果当前线程是 设置了打断标记  acquireQueued() 把当前的打断标记清空 返回 true 
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {
        // 在这里重新进行打断
    	selfInterrupt();
    }
}
// 设置打断标记
static void selfInterrupt() {
    Thread.currentThread().interrupt();
}
队列里面添加一个结点 添加到队列的后面
private Node addWaiter(Node mode) {
    // 构造一个结点
    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;
        }
    }
    // 如果尾结点为空 y也就是第一次的时候才会执行到这里
    enq(node);
    return node;
}
private Node enq(final Node node) {
    for (;;) {
        // 重新获取尾结点
        Node t = tail;
        if (t == null) { // Must initialize
        尾结点如果是空的话 设置一个空的 `头结点`
            if (compareAndSetHead(new Node()))
            // 尾结点 = 头结点
                tail = head;
        } else {
            和上面一样 cas 设置 `尾结点` 为尾结点 也就是头结点的后一个 
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}
尝试获取锁 公平锁
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 0为默认状态
    if (c == 0) {
        如果持有锁的不是当前线程 && cas成功 && 设置锁的持有者为当前线程
        if (!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");
        // 线程的状态  state++ 可重入锁 
        setState(nextc);
        return true;
    }
    // 其他的情况 队列为空 或者 获取锁失败 ...  
    return false;
}
true 如果有当前线程前面的线程排队
false 如果当前线程是在队列的头部或队列为空
public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    
    头结点 != 尾节点 && 头结点的后一个不能为空 && 当前持有锁的线程不是当前线程
    -> `头结点的后一个结点 是当前线程 false 取反 去尝试获取锁`
    -> `队列为空 或者 头结点的后一个结点 不是当前线程 true 取反 不去尝试获取锁`
    return h != t &&  ((s = h.next) == null || s.thread != Thread.currentThread());
}
/**
 公平锁的尝试获取 
 以独占不间断模式获取已在队列中的线程。 由条件等待方法以及获取使用。
   参数:
节点——节点
         arg – 获取参数
 返回:
如果在等待时中断,则为true
 */
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);
                // 头结点的 后一个节点 设置为null  相当于把头结点移除
                p.next = null; // help GC
                // 当前不是失败的了
                failed = false;
                // 返回是否被打断过的标记 
                // 如果是第二个结点  并且第一次尝试获取锁 获取成功了 就返回false
                // 如果是第二个结点 并且第一次尝试获取锁失败  进出下面的if 代码块 
                // 如果是其他结点 肯定被中断 返回 true
                return interrupted;
            }
    	 // 如果当前线程安全的被中断  并且 已经中断当前线程(线程可能一直在这里被打断 直到被唤醒)  返回之前是否被打断过 
            if (shouldParkAfterFailedAcquire(p, node) &&  parkAndCheckInterrupt())
                中断标志设为true
                interrupted = true;
        }
    } finally {
        最后 没有任何异常的情况下 不会执行  
        发生异常了 取消正在进行的获取尝试
        if (failed)
            cancelAcquire(node);
    }
}
检查和更新未能获取的节点的状态。 如果线程应该阻塞,则返回 true。 这是所有获取循环中的主要信号控制。 要求 pred == node.prev。
参数:
pred – 节点的前任持有状态
节点——节点
返回:
如果线程应该阻塞,则为true

指示线程已取消的 waitStatus 值
static final int CANCELLED =  1;  代表等待超时或者中断
指示后继线程需要解停的waitStatus 值
static final int SIGNAL    = -1;  代表需要等待其他线程唤醒
waitStatus 值指示线程正在等待条件
static final int CONDITION = -2;
指示下一个acquireShared 应无条件传播的waitStatus 值
static final int PROPAGATE = -3;
CANCELLED: 在同步队列中等待的线程等待超时或被中断,需要从同步队列中取消该Node的结点, 其结点的waitStatus为CANCELLED,即结束状态,进入该状态后的结点将不会再变化
SIGNAL: 只要前置节点释放锁,就会通知标识为SIGNAL状态的后续节点的线程
CONDITION: 该节点目前处于Condition队列中。它将不会被用作同步队列节点,直到传输时,状态将被设置为0
PROPAGATE:共享模式下,PROPAGATE状态的线程处于可运行状态

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    前一个结点的状态
    int ws = pred.waitStatus;
    如果前一个结点的状态是-1 说明他也需要被唤醒 后面的结点可以安全的被中断 直接返回true就行 
    if (ws == Node.SIGNAL)
        return true;
    前一个结点是 中断 或者 超时等待 就需要把他移除
    if (ws > 0) {
        do {
            给 pred 重新赋值 为 他的前一个结点
            当前结点的前一个结点为 新的结点  
            目的是吧前面 结点状态 = 1 的删除
            node.prev = pred = pred.prev;
    	直到新的  前一个的节点的状态 不是 中断 或者超时等待 
        } while (pred.waitStatus > 0);
        在这里切断与旧的结点的联系 移除中断的结点
        但是在这里不知道前一个结点的具体状态 返回 false
        pred.next = node;
    } else {
        waitStatus 必须为 0 或 PROPAGATE。表明我们需要一个信号,但不要停车。呼叫者将需要重试以确保其无法在停车前获取。
        就是只要结点 当前结点的前一个结点 的状态是 可共享或者其他状态 就说明 锁已经被占用 后面的需要被唤醒
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}
停车然后检查是否中断的便捷方法
返回:
如果被中断则为true
private final boolean parkAndCheckInterrupt() {
    中断当前线程
    当前线程无限期等待中......
    LockSupport.park(this);
    返回当前线程是否被其他线程触发过中断请求,也就是thread.interrupt()
    如果有触发过中断请求,那么这个方法会返回当前的中断标志true,并且对中断标志进行复位。
    return Thread.interrupted();
}

释放锁

释放锁就简单了  锁释放 非公平锁 和 公平锁释放是一样的
public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    // 尝试释放锁 
    if (tryRelease(arg)) {
        // 如果完全释放
        Node h = head;
        // 如果头结点不为空 并且 状态不为0
        if (h != null && h.waitStatus != 0)
        	// 唤醒后续结点
            unparkSuccessor(h);
            // 返回解锁成功
        return true;
    }
    return false;
}
重入锁未解锁完成 返回false
protected final boolean tryRelease(int releases) {
    // 锁的状态 -1 
    int c = getState() - releases;
    // 如果当前线程不是 锁的持有者 抛个异常
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    // 如果 c == 0 说明当前这个锁 重入的 都已经释放完了
    boolean free = false;
    if (c == 0) {
        free = true;
        // 设置当前持有锁的线程 为 null
        setExclusiveOwnerThread(null);
    }
    // 最后更新锁的状态 直接进行更新 并放到最后
    setState(c);
    // 最后返回当前锁 是否被完全释放
    return free;
}
唤醒后续结点 node 头结点 
private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
     // 如果小于0 安全状态
    int ws = node.waitStatus;
    if (ws < 0)
    // 设置头结点状态 为 0 
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
     后一个节点
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        // 从尾结点开始 倒着往前找 到 head 为止  找到一个 状态 为 -1 的node 节点 
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
            相当于从前往后找第一个 state = -1 的node
            s = t;
    }
    // 如果存在 一个node 的状态 == -1  或者 <0  直接唤醒 
    if (s != null)
        LockSupport.unpark(s.thread);
}

非公平锁

非公平锁
/**
 * Performs lock.  Try immediate barge, backing up to normal
 * acquire on failure.
 */
final void lock() {
    进来直接cas  不成功 执行 acquire
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
    // 和 公平锁一样 不同的是重写了  tryAcquire 方法 直接使用 sync 的 非公平尝试
        acquire(1);
}
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
    // sync 的 实现
    return nonfairTryAcquire(acquires);
}
// 非公平的尝试
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 如果当前 锁的状态 == 0 再次进行尝试 
    `公平锁 区别 就是 公平锁 cas 前会执行 !hasQueuedPredecessors()  ` 
    `这个方法 主要是判断当前线程是否位于同步队列中的第一个。如果是则返回true,否则返回false。`
    `综上,公平锁就是通过同步队列来实现多个线程按照申请锁的顺序来获取锁,从而实现公平的特性。非公平锁加锁时不考虑排队等待问题,直接尝试获取锁,所以存在后申请却先获得锁的情况。`

    if (c == 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;
    }
    // 失败返回 false
    return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值