上节带大家学习了它的基本使用,我们可以了解到它是一个可重入锁,下面我们就一起看一下它的底层实现~,我们在使用的时候,都是先new它,所以我们先看下它的构造函数,它主要有两个:,从字面上看,它们之间的不同点在于fair,翻译过来就是公平的意思,大体可以猜到它是用来构建公平锁和非公平锁,在继续往下看源码之前,先给大家科普一下这两种锁。,这种锁的优点很明显,每个线程都能够获取资源,缺点也很明显,如果某个线程阻塞了,其它线程也会阻塞,然而cpu唤醒开销很大,之前也给大家讲过。,优缺点正好和上边相反,优点减少开销,缺点也很明显,可能会导致一直获取不到锁或长时间获取不到锁。,好,有了基本概念之后,我们继续往下看。,首先,我们看下非公平锁,默认情况下,我们申请的都是非公平锁,也就是new ReentrantLock(),我们接着看源码。,它继承了Sync,Sync是一个内容静态抽象类:,分为公平和非公平,使用AQS状态来表示持锁的次数,在构造函数初始化的时候都有sync = ...,我们接着看NonfairSync。在使用的时候,我们调用了lock.lock()方法,它是ReentrantLock的一个实例方法。,实际上内部还是调了sync的内部方法,因为我们申请的是非公平锁,所以我们看NonfairSync下的lock实现:,compareAndSetState这个方法,是AQS的内部方法,意思是如果当前状态值等于预期值,则自动将同步状态设置为给定的更新值。此操作具有volatile读写的内存语义。,可以看到执行lock方法,会通过AQS机制计数,setExclusiveOwnerThread设置线程独占访问权限,它是AbstractOwnableSynchronizer的一个内部方法,子类通过使用它来管理线程独占。,可以看到它是继承了AbstractOwnableSynchronizer。下面接着看,我们说如果实际值等于期望值会执行上边的方法,不期望的时候会执行acquire(1)。,这个方法以独占模式获取,忽略中断,它会尝试调用tryAcquire,成功会返回,不成功进入线程排队,可以重复阻塞和解除阻塞。看下AQS 内部的这个方法。,我们可以看到实现肯定不在这,它的具体实现在NonfairSync。,可以看到它调用了,nonfairTryAcquire方法,这个方法是不公平的tryLock,具体实现在Sync内部,这里我们要重点关注一下。,好,我们再回过头看下 acquire。,selfInterrupt很好理解,线程中断。,其实我们关注的重点是这个方法acquireQueued,首先关注一下入参,它内部传入了一个addWaiter,最后它回NODE节点。,我们可以大体从猜到,Node是一个等待队列的节点类,是一个链表结构,之前我们讲FutureTask源码的时候也遇到过这种结构,它通常用于自旋锁,在这个地方,它是用于阻塞同步器。,好,下面我们关注一下 acquireQueued。,从上面的源码来看,在体会一下上面讲的非公平锁的概念,是不是更好理解一些,然后就是释放锁unlock,这个方法我们可以看到是ReentrantLock下的一个实例方法,所以公平锁的释放锁也是调的这个方法,其实最终可以猜到调用的还是sync的方法。,Sync继承AQS,release是AQS的内部方法。,我们再看下tryRelease, 同样这个实现在Sync内。,公平锁FairSync的区别在于,它的获取锁的实现在它的内部,Sync默认内部实现了非公平锁。,它的实现比较简单,通过实现可以发现,它按照申请锁的顺序来获取锁,排第一的先拿到锁,在结合上面的概念理解一下,就很好理解了。,释放锁unlock,上面我们已经讲过了。,本节内容可能有点多,主要是看源码,可以打断点自己调一下, 举一反三,通过源码去理解一下什么是公平锁和非公平锁, ReentrantLock可重入锁体验在哪里。
© 版权声明
文章版权归作者所有,未经允许请勿转载。