您的位置:首页 > 编程语言 > Java开发

ReentrantLock原理分析

2017-08-13 00:00 344 查看
ReentrantLock 重入锁是对 synchronized 的一种补充,ReentrantLock 提供了可定时、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。与 synchronized 相比, ReentrantLock 更加灵活可控,伸缩性更好。ReentrantLock 的非公平锁性能也比 synchronized 更好。
通过对 CAS 的了解,我们知道 CAS 底层也是通过排它锁实现的,只不过 CAS 是 CPU 触发的,效率更高。ReentrantLock 实现方式和 AtomicInteger 方式类似,不过 ReentrantLock 借助 AbstractQueuedSynchronizer 类来实现独占锁的功能。

ReentrantLock 主要方法如下:

ReentrantLock 构造函数,传入 boolean 参数标明是公平锁还是非公平锁,默认是非公平锁;

lock 获取锁,lock 获取锁如果成功直接返回,如果失败则阻塞等待;

lockInterruptibly 支持中断获取锁,lock 获取锁如果成功直接返回,如果失败则阻塞等待,并支持中断操作,

tryLock 获取锁,tryLock 没有设置超时时间时,获取锁成功或者失败都直接返回,tryLock 设置超时时间时,最多等待超时时间后返回结果,并支持中断操作;

unlock 释放锁,unlock 释放锁唤醒等待队列的第一个线程。

ReentrantLock 结构:

public class ReentrantLock implements Lock, Serializable {
private static final long serialVersionUID = 7373984872572414699L;
private final ReentrantLock.Sync sync;

public ReentrantLock() {
this.sync = new ReentrantLock.NonfairSync();
}

public ReentrantLock(boolean var1) {
this.sync = (ReentrantLock.Sync)(var1?new ReentrantLock.FairSync():new ReentrantLock.NonfairSync());
}

public void lock() {
this.sync.lock();
}

public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}

public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}

public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

public void unlock() {
sync.release(1);
}
}

ReentrantLock 获取锁可以通过 lock 和 tryLock 获取,lock 方法获取时,如果所没被占用直接获取,如果被本线程占用,则直接获取,否则加入等待队列,并阻塞线程;tryLock 方法获取时,如果所没被占用直接获取,如果被本线程占用,也直接获取,如果被其他线程占用,则立刻返回失败。
从 ReentrantLock 中我们可以看到 ReentrantLock 的锁是通过 Sync 这个类完成的,Sync 则继承自 AbstractQueuedSynchronizer,AQS 是独占锁和共享锁的父类,通过 AQS 的 compareAndSetState 方法来进行加锁从而实现独占锁的功能。
Sync 有两个子类,分别是 FairSync 和 NonfairSync。

NonfairSync 结构:

/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;

/**
* Performs lock.  Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}

protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}

NonfairSync 则先尝试获取锁,如果获取失败则再加入等待队列。ReentrantLock 默认是非公平锁。

FairSync 结构:

/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;

final void lock() {
acquire(1);
}

/**
* Fair version of tryAcquire.  Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
}

FairSync 判断是否有线程等待,如果没有则尝试获取锁,如果有则加入到等待队列。

AQS 结构:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable {
private static final long serialVersionUID = 7373984972572414691L;
private transient volatile AbstractQueuedSynchronizer.Node head;
private transient volatile AbstractQueuedSynchronizer.Node tail;
private volatile int state;
static final long spinForTimeoutThreshold = 1000L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;

protected AbstractQueuedSynchronizer() {
}

protected final boolean compareAndSetState(int var1, int var2) {
return unsafe.compareAndSwapInt(this, stateOffset, var1, var2);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
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);
}
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
}

ReentrantLock 是通过使用 AQS 类来实现的,ReentrantLock 调用 lock 方法时,调用 AQS 的 acquire 方法,acquire 方法则调用子类 tryAcquire 方法,子类 tryAcquire 方法则分别有个 NonFairSync 和 FairSync 实现,如果获取失败则加入到等待队列中去。ReentrantLock 调用 unlock 方法时,调用 AQS 的 release 方法,release 方法则调用子类 tryRelease 方法,子类 release 成功后,则唤醒等待队列的第一个线程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java