我们之前介绍了AbstractQueuedSynchronizer(AQS)的基本原理,它是同步器基础的功能实现,其中它的tryAcquire()功能实现,都是交给子类来实现的,下面我们介绍下,基于AQS实现,可重入锁功能的ReentrantLock。 可重入意为一个持有锁的线程,可以对资源重复加锁而不会阻塞,同时ReentrantLock还定义了公平与非公平策略,默认是使用非公平策略。所谓公平策略就是先到先得,保证公平性,但是却增大了线程的切换。非公平策略,减少了线程切换,但是由于不公平的特性,造成某些线程长期没有分配到cpu,处于饥饿状态。
ReentrantLock的构造函数
我们先观察ReentrantLock的构造函数,它有两个构造函数,默认使用的是非公平锁。
其中NonfairSync,FairSync的继承Sync,同时Sync继承AbstractQueuedSynchronizer,类图例子:
lock方法实现,是交给具体的公平锁和非公平锁
非公平锁的实现机制:
这里调用compareAndSetState(0, 1)方法,用CAS方法进行设置加锁,这里的话,是放开线程之间的抢占的,就看那个线程能抢到,设置锁的状态成功,那么就可以设置当前线程为全局变量线程,这样确保自己可以重入,如果加锁失败,就会调用acquire(1)进入排队。
下面是acquire的逻辑:
我们之前介绍的AQS tryAcquire功能是交给子类实现的,那么非公平策略下的tryAcquire是如何实现的呢?会直接调用NonfairSync的nonfairTryAcquire方法。
它的过程:获取当前状态如果为0,那么进入状态抢占阶段,如果状态设置成功,那么将当前线程设置为全局线程,如果state不为0,并且当前线程与全局线程相等,那么锁的状态加1,设置状态
公平锁的实现机制:
它与非公平锁的机制实现,基本类似,只是在状态等于0的时候,进入状态判断时,增加了一个hasQueuedPredecessors函数,判断当前节点是否在头节点之后如果是的话,则进入状态设定的判断,这样保证了一定的公平性。
锁释放机制:
这里公平锁与非公平锁的释放机制是一样的,因为存在线程的重入加锁,状态会进行重复累加,所以需要将状态进行扣减,如果当前线程不是全局锁持有线程,那么抛出异常,之后如果状态为0,那么设置free为true,全局线程设置为null,之后设置全局状态信息
lockInterruptibly的含义:
在循环获取锁的过程中,如果检测到interrupt标志为true,抛出InterruptedException异常,交由外部应用处理,而lock则是忽略掉中断标记的
tryLock()方法
去尝试获取锁信息,一旦获取成功则返回true,失败则返回false
tryAcquireNanos(int arg, long nanosTimeout)
等待指定的时间内获取锁
总结
了解可重入锁ReentrantLock的机制,同时对于公平机制和非公平机制的熟悉lock和release的底层机制熟悉常用的一些tryLock,lockInterruptibly的熟悉