可重入锁(ReentrantLock)
介绍ReentrantLock类就需要讲到AQS(AbstractQueuedSynchronizer,抽象队列同步器)了,因为ReentrantLock内部加锁操作的实现是调用的内部类Sync及其子类NonfairSync和FairSync的lock()方法,而Sync是直接继承的AbstractQueuedSynchronizer类。
以下是ReentrantLock的lock()方法的源码和内部类Sync的继承关系:
public void lock() {
sync.lock();
}
//ReentrantLock的属性
private final Sync sync;
//内部类Sync的继承关系
abstract static class Sync extends AbstractQueuedSynchronizer
AQS(AbstractQueuedSynchronizer)
AQS全称AbstractQueuedSynchronizer,抽象队列同步器。java并发包下很多API都是基于AQS来实现的加锁和释放锁等功能的,如ReentrantLock和ReentrantReadWriteLock,AQS是java并发包的基础类。
ReentrantLock和AQS之间的关系:
ReentrantLock内部包含了一个继承自AQS的内部类对象,这个对象就是sync,是ReentrantLock可以实现加锁和释放锁的关键性的核心组件。
AQS类内部的属性:
/**
* Head of the wait queue, lazily initialized. Except for
* initialization, it is modified only via method setHead. Note:
* If head exists, its waitStatus is guaranteed not to be
* CANCELLED.
*/
private transient volatile Node head;
/**
* Tail of the wait queue, lazily initialized. Modified only via
* method enq to add new wait node.
*/
private transient volatile Node tail;
/**
* The synchronization state.
*如果为0代表没有加锁,大于0则代表对当前占有锁的线程加锁的次数
*/
private volatile int state;
此外还有一个很重要的属性,是继承自AbstractOwnableSynchronizer类的,是Thread类的exclusiveOwnerThread,这个是记录当前占着锁的线程。这个AbstractOwnableSynchronizer类主要就是exclusiveOwnerThread属性和它的set方法和get方法。
AQS类继承关系:
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable
/**
* The current owner of exclusive mode synchronization.
* 记录当前占着锁的线程
*/
private transient Thread exclusiveOwnerThread;
AQS类里面有一个Node内部类,主要是为了存储等待加锁的线程,这个是结点的实现。此外在AQS类里面保存了这个双向链表的头结点和尾结点。
ReentrantLock加锁和释放锁的底层原理
默认是非公平锁,非公平锁的吞吐量大,但是可能会导致线程饿死,也就是存在如果多个线程同时抢锁,可能会出现其中一个线程一直占着锁,但是其他线程一直抢不到锁的情况。
非公平锁
ReentrantLock中非公平锁是通过内部类NonfairSync实现的。
ReentrantLock的无参构造:
public ReentrantLock() {
sync = new NonfairSync();
}
说明默认的是非公平锁。
非公平锁的加锁过程
现在如果有一个线程过来尝试用ReentrantLock的lock()方法进行加锁,会调用sync的lock()方法
1.ReentrantLock的lock()方法:
public void lock() {
sync.lock();
}
2.执行sync的lock()方法:
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
3.首先方法执行CAS操作将state的值从0变为1,如果执行成功,则设置占有锁的线程为当前线程,加锁成功。
CAS方法:
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
4.如果CAS没有成功,代表当前的state不为0,则有两种可能,第一种是已经被其他线程占有了,第二种是被当前线程占有,执行acquire()方法,acquire()方法在Sync和NonfairSync中都没有重写,因此执行的还是AQS中的方法过程。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
5.首先执行tryAcquire()方法,这个方法是尝试加锁,如果加锁成功则短路不执行后续方法,如果加锁失败则将调用acquireQueued()方法用CAS将当前线程加入等待队列也就是AQS中的双向链表中,不断尝试加锁。
NonfairSync类中的tryAcquire()方法:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
Sync类中的nonfairTryAcquire()方法:
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
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;
}
首先获取当前的线程,然后获取state的值,如果这时state的值为0(可能在从第一次CAS到此处的判断时间里,其他线程释放锁了),则再用CAS将state的值从0改为1,然后设置占有锁的线程为当前线程然后返回true,加锁成功。如果不是0则判断占有锁的线程是否为当前线程,如果是则将state的值加一,不过在这之前会判断是否超出了int类型的最大值,然后加锁成功,返回true。如果当前锁被占用且不是当前线程占用的则返回false,然后执行acquireQueued()方法,参数为addWaiter(Node.EXCLUSIVE)和1。
addWaiter()方法:将当前线程加入等待队列中
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
acquireQueued()方法:等待队列中的线程不断的尝试加锁,加锁成功则退出死循环
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
非公平锁的释放锁的过程
调用ReentrantLock的unlock()方法
1.ReentrantLock的unlock()方法:
public void unlock() {
sync.release(1);
}
2.执行sync的release()方法:
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
3.首先执行tryRelease()方法,参数为1,如果释放成功则返回true
Sync中的tryRelease()方法:
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
首先定义一个局部变量存一下当前的state释放一次锁即减1后的值,然后判断当前的线程是否是占有锁的线程,如果不是则抛出异常,如果是且释放一次锁后的值是0则更改当前占有锁的线程为null,并且更改state的值然后返回true,释放成功。如果不为0则代表锁依然由当前线程持有,只是释放了一次而已。
总结:释放锁的过程就是不断的将AQS内的state变量的值递减1,如果state值为0,则彻底释放锁,会将exclusiveOwnerThread变量也设置为null。
公平锁
ReentrantLock中公平锁是通过内部类FairSync实现的。
ReentrantLock的有参构造:如果为true则为公平锁,false为非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁的加锁过程
1.ReentrantLock的lock()方法:
public void lock() {
sync.lock();
}
2.FairSync中的lock()方法
final void lock() {
acquire(1);
}
3.AQS中的acquire()方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
4.FairSync中的tryAcquire()方法
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
首先获取当前线程,然后获取当前的state的值,如果state为0的话判断是否轮到当前线程获取锁,如果队列中有线程在当前线程之前则hasQueuedPredecessors()方法返回为true,如果队列是空的或者当前线程在队列的头部则返回为false,如果返回为false则用CAS将state的值由0改为1,并且设置占有锁的线程为当前线程,加锁成功,返回true。如果为true则代表还未轮到当前线程。如果不为0且占有锁的线程为当前线程的话,则state加一,如果超出int类型的最大值则抛出错误,加锁成功,返回true。否则加锁失败,并将当前线程加入等待队列中,然后不断的去请求加锁。
公平锁的释放锁的过程
与非公平锁一致。
线程间通信
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public static void main(){
//线程1启动
lock.lock();
try {
//改变条件的语句
condition.signalAll();
}catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
//线程2启动
lock.lock();
try{
while(//条件不满足时等待){
condition.await();
}
//等改变条件后满足当前的条件可执行以下业务
}catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}