可中断获取锁与超时等待获取锁源码分析


可中断式获取锁

  • 可响应中断式锁可调用方法lock.lockInterruptibly();该方法的底层会调用AQS的acqireInterruptibly方法;

acquireInterruptibly()方法:

public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    //这里会先检查是否有被中断,如果有则抛出一个中断异常
    //否则尝试去获取同步状态,成功直接退出,失败则进入doAcquireInterruptibly(arg)方法
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

doAcquireInterruptibly()方法:

  • 如果当前线程的前驱节点为队头时,尝试获取同步状态
    若获取成功则将队头节点出队,当前线程置为持有锁线程,并将队头指针指向当前线程所封装的节点,否则不断自旋直到获取成功或者线程被中断
/**
 * Acquires in exclusive interruptible mode.
 * @param arg the acquire argument
 */
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())
                //线程被阻塞时若检测到中断抛出中断异常后退出。
                throw new InterruptedException();
        }
    } finally {
        //获取同步状态失败将当前节点取消
        if (failed)
            cancelAcquire(node);
    }
}

超时等待获取锁(tryAcquireNanos()方法)

  • 调用lock.tryLock(timeout,TimeUnit)方式
  • boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  • 超时等待锁的返回条件:
    1. 在指定时间内获取到锁
    2. 在指定时间内没有获取到锁
    3. 在指定时间内被中断
public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
  • 该方法调用AQS的tryAcquireNanos()方法:先判断是否被中断,然后尝试获取同步状态
    如果成功则直接返会,否则进入到doAcquireNanos()方法:
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    return tryAcquire(arg) ||
        doAcquireNanos(arg, nanosTimeout);
}

doAcquireNanos()方法:

/**
 * Acquires in exclusive timed mode.
 *
 * @param arg the acquire argument
 * @param nanosTimeout max wait time
 * @return {@code true} if acquired
 */
private boolean doAcquireNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    //如果设置的时间不合法,直接返回
    if (nanosTimeout <= 0L)
        return false;
    //计算截止时间
    final long deadline = System.nanoTime() + nanosTimeout;
    //尝试将当前节点插入到同步队列
    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 true;
            }
            //重新计算超时时间
            nanosTimeout = deadline - System.nanoTime();
            //如果超时直接返回
            if (nanosTimeout <= 0L)
                return false;
            //线程阻塞等待
            if (shouldParkAfterFailedAcquire(p, node) &&
                nanosTimeout > spinForTimeoutThreshold)
                LockSupport.parkNanos(this, nanosTimeout);
            //若线程被中断则抛出中断异常
            if (Thread.interrupted())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值