zoukankan      html  css  js  c++  java
  • ReentrantLock.tryLock

    通常使用 ReentrantLock.tryLock 的时候,都会带上一个时间戳,如果到了时间仍然没获取锁返回 false。

    不带时间戳,当前线程只会尝试获取一次锁,然后返回结果;带上时间戳,则当前线程在等待时间内会多次尝试获取锁。

    这里面细节还挺多,在等待时间内,线程是否会挂起?

    如果挂起,是怎么挂起的?线程如何醒来?

    如果不挂起,又怎么去做?

    static final long spinForTimeoutThreshold = 1000L;
    
    // java.util.concurrent.locks.AbstractQueuedSynchronizer#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;
        // 先把节点加入到等待队列的尾部,等待队列是一个带头节点的双向链表
        // node 是当前节点,node.thread 是 currentThread
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                // 如果 node 的前驱节点是头节点,则尝试修改 state 值,获取锁
                if (p == head && tryAcquire(arg)) {
                    // 这种情况只发生在队列中只有一个等待节点
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                // 判断是否到期
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    // 到期返回 false,先执行 finally 代码块
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    // 如果 nanosTimeout 大于自旋的时间,则直接挂起线程
                    // 在 nanosTimeout 时间后,线程自动醒来,从此处继续执行 for 循环
                    // 如果 nanosTimeout 小于自旋的时间,则当前线程一直自旋,执行 for 循环,直到获取锁,或者过期返回 false
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            // 线程最终获取锁失败,把节点从等待队列中移除
            if (failed)
                cancelAcquire(node);
        }
    }
  • 相关阅读:
    【2020-05-03】发掘自己内心那个原点的力量
    【2020-05-02】要适应不确定性
    【2020-05-01】人生十三信条
    【一句日历】2020年5月
    【2020-04-30】每一句话,都是自我学习
    【2020-04-29】勤奋是一种享受
    【2020-04-28】自我观念强化的实践
    【2020-04-27】自我提升的里程碑
    【2020-04-26】还在温室里的自己
    家谱树(信息学奥赛一本通 1351)
  • 原文地址:https://www.cnblogs.com/allenwas3/p/13168270.html
Copyright © 2011-2022 走看看