AQS,ReentrantLock和ConditionObject


介绍一下AQS:

注意看绿色的方法,这些是对外开放的方法。

另外,AQS是一个CLH变种双边队列,原始的CLH是.net人员设计的,他们设计的时候是让每个阻塞在队列上的线程不停的自旋,而在java中借鉴了这种设计方式,但是不再是自旋,而是通过LockSupport.park(this);这样一个方法将线程阻塞。

***********************

acquire方法:

  其中acquire开头的方法是AQS默认实现的通用加锁方法,带有Interruptibly结尾的是处理打断状态的请求方法,不带的是不处理打断标志的方法。带有shared的是共享锁的加锁方法,不带有的则是独占锁的加锁方法。

 上面是AQS中的acquire方法(AQS实现的这个是公平锁的获取方式):独占锁获取方法,先调用tryAcquire方法,如果成功则加锁成功,如果失败则线程开始排队,并阻塞自己。tryAcquire方法如下:

方法的注释解释的很清楚,子类应该去实现这个方法,因为此方法会被acquire方法调用,而独占锁获取锁必须调用acquire方法,如果你实现的是一个独占锁,那么你必须实现此方法,如果是共享锁则不必。

实现此方法时:当返回失败,则此线程应该排队(直到被另外一个线程通过release唤醒或者它被中断),如果成功则上锁成功。

******************

release方法:

  release方法是AQS释放阻塞线程的方法,让其去竞争锁,带有shared是共享锁的释放方法,不带的则是独占锁的方法。思路一致。这里看下公平锁的release方

 注释很清楚,AQS负责释放阻塞线程,子类实现自己的tryRelease方法去释放锁。其他的方法就不赘述了。

*************************

介绍下ReentrantLock:

  ReentrantLock是实现AQS的独占锁,它内部先是定义了一个抽象同步器Sync实现了AQS,这个方法定义了非公平锁尝试获取锁的方式(尝试获取锁是不会阻塞的,只会返回成功或失败)。

然后是公平锁和非公平锁:

   结合之前AQS的介绍,相信我们一眼就可以看透这两个类了,非公平锁的lock方法是自己利用CAS实现的抢占式加锁,如果失败则专用AQS的公平锁加锁方式;而公平锁就简单多了lock方法调用的就是AQS提供的加锁方式。

  而尝试获取锁的方式都是自定义的,前者定义在sync中后者定义在公平锁子类中。代码不复杂,不需要赘述了。

 **************************

介绍下ConditionObject:

  这个是条件队列,相信很多人看到这个类的时候是很迷惑的,我也是。别慌先看类的方法:

 就俩类方法await和signal,分别是阻塞和唤醒。还有两个属性Node,说明这是个双端链表结构的组织,因为有前驱和后驱两个节点。用大母脚趾头想都能想到这个类是干啥用的。就不赘述了。

---------------------------------------------

ReentrantLock测试:

ConditionObject测试:

  线程2和线程3是前两个进入锁的线程因为各自调用count+1后,但是不满足Condition的条件,因此被阻塞到Condition1对象上,然后后面进来的所有线程都满足Condition队列的要求,因此可以直接执行。可以看到除了第2和第3线程外,其他线程都是顺序执行(按照非公平锁的CLH队列顺序执行)。

  调用Lock的newCondition方法会创建一个绑定到此Lock上的阻塞队列Condition,这个Condition又叫做条件队列,当没有满足此Condition的条件前,锁是由获得Lock的当前线程占有,当满足Condition的条件后,可以调用Condition.await方法,这样当前线程会以原子的方式释放掉此Lock,然后阻塞在Condition的阻塞队列中,直到被同一个Condition唤醒或者此线程被打断。

!!!!

如有错误,请指正。

相关