ReentrantLock源码分析

Posted 技术无产者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock源码分析相关的知识,希望对你有一定的参考价值。

1.代码优化的设计

非公平模式下:

非公平锁的加锁流程,线程在进入同步队列等待之前有两次抢占锁的机会:

  • 第一次是非重入式的获取锁,只有在当前锁未被任何线程占有(包括自身)时才能成功;
  • 第二次是在进入同步队列前,包含所有情况的获取锁的方式。

只有这两次获取锁都失败后,线程才会构造结点并加入同步队列等待。

有的博客说写两次获得锁的逻辑虽然减少了代码的简洁,但这种对非重入且虽然队列中有线程在等待获取锁,但是在等待的线程在获取锁之前,这个新来的线程提前去占据了锁,提高了性能,我觉得应该是新的线程避免执行

final Thread current = Thread.currentThread();

int c = getState();//获得锁状态

这俩行代码,少执行两行代码,就算和阻塞线程同时抢占锁,因为少执行两行代,码也提高了新线程获取到锁的可能性??? 或者线程在进入等待队列前可以进行两次尝试,这能大大增加了获取锁的机会??? 

并且这个ReentrantLock多次用到了这个思想,入队在enq()这个方法那也用到了这种思想,以后再回来补充。

  final void lock() 
            if (compareAndSetState(0, 1)) //第一次CAS尝试获取锁 这行代码删了也不影响正常业务逻辑
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        


   final boolean nonfairTryAcquire(int acquires) 
            final Thread current = Thread.currentThread();
            int c = getState();
          //第二次CAS尝试获取锁
            if (c == 0)  
                if (compareAndSetState(0, acquires)) 
                    setExclusiveOwnerThread(current);
                    return true;
                
            
            else if (current == getExclusiveOwnerThread()) 
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            
            return false;
        

2.非公平模式下抢占锁

      当新线程来抢占锁时,正好占据锁的线程释放了锁,虽然他会唤醒队列中阻塞的线程,但是当阻塞的线程唤醒去重新获取锁时发现锁又被占据后,由于外层循环for(::) 虽然被唤醒,但获得不了锁,又会继续陷入阻塞,只有当当前节点获得到了锁才会head才会被设置为当前节点,否则就算头节点所代表的线程释放了锁,而这时候碰巧这个锁被新来的线程所抢占,他也不会被清除,只是这个时候它表示一个空结点,下次还可以用这个head唤醒后续节点。

 当新的线程来抢占锁时,如果直接CAS抢到了,提高性能的地方在于:

1>它是不需要再额外封装成Node节点来放到CLH队列中,这样节省了封装Node,入队所消耗的时间(主要原因)

2>由于就算这个新线程抢到了锁,头节点还是会唤醒阻塞队列中的线程来尝试获取锁,只是因为锁被其它线程获得,它会重新陷入阻塞罢了,但是如果公平模式下多个线程同时入CLH队列,往尾部插时还会CAS竞争tail节点,失败,浪费资源,如果其中一个获得到了锁就无需考虑这个节点入队的消耗了

3.唤醒节点时,从尾部往头节点找的原因

do 
            node.prev = pred = pred.prev;
         while (pred.waitStatus > 0);
        pred.next = node;

某些线程封装成节点存在CLH队列中后,但是可能存在该线程主动放弃获得资源了,轮到它是就不需要把资源给它了,所以这个从后往前找就是为了清除这些节点

4:源码详解

从源码角度彻底理解ReentrantLock(重入锁) - takumiCX - 博客园[TOC] 1.前言 在 "ReentrantLock(重入锁)功能详解和应用演示" 这篇文章里我们讲解并演示了ReentrantLock(重入锁)的各种功能,其中就谈到Reenthttps://www.cnblogs.com/takumicx/p/9402021.html

以上是关于ReentrantLock源码分析的主要内容,如果未能解决你的问题,请参考以下文章

ReentrantLock源码分析

[源码分析]ReentrantLock & AbstractQueuedSynchronizer

ReentrantLock源码分析-JDK1.8

源码分析ReentrantLock实现原理

ReentrantLock源码分析

ReentrantLock源码分析