• 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);
        }
    }
  • 相关阅读:
    自定义异常处理
    遍历目录
    快速排序
    Map<String,String>转换json字符串
    Sublime Text 3破解
    替换字符串
    Moss2007迁移步骤
    Sharepoint 2010 定时提醒
    Sharepoint 2010 显示详细错误
    Sharepoint 2010 安装完Micrsoft sharepoint 2010 service pack 1后网站主页报错
  • 原文地址:https://www.cnblogs.com/allenwas3/p/13168270.html
Copyright © 2020-2023  润新知