模拟AQS中acquireQueued返回true的情况

AQS中有acquire方法:

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

    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; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

上面的acquire方法用在ReentrantLock.FairSync,ReentrantLock.NonfairSync,ReentrantReadWriteLock.WriteLock,ThreadPoolExecutor.Worker类中的lock方法,加锁过程中如果失败就会进入队列(可能一开始就在队列)反复阻塞被唤醒直到成功获取锁,在此过程中,线程可能面临中断,acquireQueued方法返回值就是在等待的过程中是否被中断,该方法应用在await(),awaitNanos(long),awaitUnti(date),await(long,TimeUnit),awaitUninterruptibly()方法中用以判断中断状态

下面是通过代码模拟线程抢锁等待过程被中断

	public static void main(String[] args) throws InterruptedException {
		Lock lock = new ReentrantLock();
		new Thread(() -> {
			try {
				lock.lock();
				Thread.sleep(1000);
				System.out.println(Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}).start();
		Thread.sleep(100);


		Thread thread1 = new Thread(() -> {
			try {
				lock.lock();
				System.out.println(Thread.currentThread().getName() + "=" + Thread.currentThread().isInterrupted());
			} finally {
				lock.unlock();
			}
		});

		Thread thread2 = new Thread(() -> {
			lock.lock();
			try {
				System.out.println(Thread.currentThread().getName() + "=" + Thread.currentThread().isInterrupted());
			} finally {
				lock.unlock();
			}
		});
		thread1.start();
        Thread.sleep(1);
		thread2.start();
        Thread.sleep(1);
		thread2.interrupt();
	}

执行上面的代码,thread2直接进入断点interrupted=true

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AQSacquireQueued方法是在tryAcquire执行失败后,用于将当前线程加入到等待队列,并在适当的时候阻塞线程。具体流程如下: 1. 首先,使用addWaiter方法将当前线程添加到等待队列,该方法会创建一个节点并将其插入到等待队列的尾部。 2. 然后,调用shouldParkAfterFailedAcquire方法来判断是否应该阻塞当前线程。该方法会根据前驱节点的等待状态来决定是否需要阻塞当前线程。 - 如果前驱节点的等待状态为Node.SIGNAL,表示前驱节点释放锁之后会唤醒当前节点,此时应该阻塞当前线程。 - 如果前驱节点的等待状态大于0,表示前驱节点取消了等待,需要将当前节点的前驱节点设置为前驱节点的前驱节点,直到找到一个等待状态不大于0的节点为止。然后将当前节点插入到该节点之后。 - 如果前驱节点的等待状态既不是Node.SIGNAL,也不大于0,则使用compareAndSetWaitStatus方法将前驱节点的等待状态设置为Node.SIGNAL,表示当前节点需要被唤醒。 3. 最后,根据shouldParkAfterFailedAcquire方法的返回值来判断是否需要阻塞当前线程。如果shouldParkAfterFailedAcquire方法返回false,表示不需要阻塞当前线程,则acquireQueued方法会一直自旋直到成功获取锁为止。如果shouldParkAfterFailedAcquire方法返回true,表示需要阻塞当前线程,则调用LockSupport.park方法阻塞当前线程,直到被唤醒为止。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [AQS核心流程解析-acquire方法](https://blog.csdn.net/IToBeNo_1/article/details/123404852)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值