ReentrantLock实现原理

来源:互联网 发布:淘宝的私人定制在哪里 编辑:程序博客网 时间:2024/05/30 04:42

看完源码记流水账系列..


这个类是concurrent包中的一个小东西,用法也很简单。说到原理的话,还的先说这个并发工具包的基础部分。


这个包提供了很多同步控制的工具,让我们可以不去用最基础的synchronized,线程间的通信也不必用notify,wait了,而且控制的精细度更加好,速度更快。最基础的部分是Unsafe类,这个类有大量的native方法实现,做的事都叫做CAS,compare-and-set,这个就是乐观锁。操作时不加锁(其实在底层操作(JNI方法中)时,读取内存值和预估值比较,然后set,这个操作还是得上锁保证原子性)。而synchronized是悲观锁,任何涉及同步的地方都强制加锁,即使冲突并没有发生,这会降低程序的速度。


在以上的基础上,我们就可以抛弃以前那套同步机制啦。在这之上有一个AbstractQueuedSynchronizer(AQS)这东西用Unsafe作为工具实现同步控制。具体原理也很直观。

1.首先这就是把锁,里面有个int值叫做state。0的时候表示可用,大于0(同一个线程可重复获取这个锁,每获取一次 +1)表示已经有人用了,就是有线程占有了,别的线程再想用得排队等待,到那等呢,到下面的queue。

2.这个抽象类维持一个队列(queue),当锁被占时,等待的线程就进来排队,后来的线程排到后面去,然后当锁可用时,排到前面的先上,就这么回事...


ReentrantLock中Sync内部类继承了AQS,重写了tryAcquire()和tryRelease()来实现它自己的功能。这个类有两个功能版本,Fair和unfair,所谓公平和非公平方式,具体在tryAcquire方法的细微差别。公平版本的tryAcquire方法中在获取锁时,先查看这个等待队列前面有没有线程在等,有的话获取锁失败,乖乖到队列里去排队,而非公平版本上就不管这个,要是刚好能获取锁,那直接占有了,这样前面等的线程就会一直等。代码上 就是hasQueuedPredecessors()这个方法

if (!hasQueuedPredecessors() &&                    compareAndSetState(0, acquires)) {
<span style="white-space:pre"></span>//......
}
不过如果等待线程全部进入队列排队了,那这些线程会按照顺序一个个来的,不管是公平还是不公平版本的锁。插队只会发生在当前线程放锁和新线程同时进入获取锁的时候。


0 0
原创粉丝点击