ReentrantLock加锁解锁大致流程

ReentrantLock 非公平锁加锁解锁简要过程, 不考虑可重入, 打断之类的细节

NonfairSync关键字段:
state: 0表示共享, 1表示已被占用, 即状态为0时可已被加锁
head, tail: 维护一个双向链表, 存的是被park的线程(具体是什么状态看waitStatus), 尾进, 头出
exclusiveOwnerThread: 当前所被哪个线程持有

加锁:
    成功:
        state被置为1 (cas)
        owner设置为当前线程
    失败 阻塞:
        1. addWaiter(Node.EXCLUSIVE): 在双线链表中加入一个节点, 关联当前线程(此时仅仅是加入, 还没有被阻塞), 返回新节点node
        2. acquireQueued(node, arg): 
            while(true)
            (1): 尝试获取锁 若成功获取, 被唤醒的线程的前驱节点(即head)从链表中移除, 然后自己作为head, 
            因为head只是作为一个方便操作的节点, 没有实际意义, 所以相当于变相把被唤醒的线程移除的链表  
            (这一步主要是为了被唤醒的线程考虑, 因为之前是阻塞再这个方法中的, 所以被唤醒后仍然在这里继续执行, 那被唤醒后的第一件事, 就是考虑争抢锁)
            (2): 获取失败, 把前驱节点的waitStatus改为-1, 然后park
        
        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;
                    }
                    // 这里park
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
    释放锁:
        1. state改为0
        2. ownerThread置为null
        3. 从双链表的头开始唤醒线程(LockSupport.unpark(s.thread);)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。