简介
ReentrantLock是一个可重入的独享锁,是平时常用的一个锁,用法和实现都比较简单,如下:
private static ReentrantLock lock = new ReentrantLock();
private static void testLock() {
for (int i=0;i<100000;i++) {
lock.lock();
try {
test++;
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
lock.unlock();
}
}
}
private static void testLock2() {
for (int i=0;i<100000;i++) {
if(lock.tryLock()) {
try {
test++;
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
lock.unlock();
}
}
}
}
private static void testLock3() throws Exception {
for (int i=0;i<100000;i++) {
if(lock.tryLock(1, TimeUnit.MINUTES)) {
try {
test++;
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
lock.unlock();
}
}
}
}
还有ReentrantLock支持可重入。
ReentrantLock是基于aqs独占模式实现的,
本文重点介绍下公平和非公平模式,和ReentrantLock实现原理。
同步器-Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
//ReentrantLock 默认是非公平模式,这里给出了非公平模式下的尝试获取锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// AbstractQueuedSynchronizer 的state常用于保存资源被占用状态,这里保存ReentrantLock锁状态,=0表示现在锁现在没被占用
int c = getState();
if (c == 0) {
// 设置成占用状态,返回true,并设置lock拥有线程为当前线程,支持可重入
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;
}
// 实现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;
}
```
}
了解AbstractQueuedSynchronizer 都知道,AbstractQueuedSynchronizer暴露tryAcquire,tryRelease让实现者自己去实现,ReentrantLock的Sync实现了这两个方法,用于判断是否可以获取锁和释放锁,接下来介绍非公平模式和公平模式
非公平模式-NonfairSync
ReentrantLock支持公平、非公平两种策略,并通过继承AQS实现了对应两种策略的同步器NonfairSync与FairSync,默认是非公平策略
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
// 这里实现 lock方法,即ReentrantLock.lock方法
final void lock() {
// 这里判断是否有其他资源占用,cas设置成功,说明当前线程获取成功,这里
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 否则申请一个资源,就是这里会调用tryAcquire方法
acquire(1);
}
//尝试获取锁资源,调用的是非公平获取锁
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
公平模式-FairSync
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
//获取锁
final void lock() {
acquire(1);
}
//公平模式和非公平模式区别就在这里,多了hasQueuedPredecessors判断,就是看是否已有等待获取锁资源线程并且不是当前线程,如果有不去竞争
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;
}
}
公平模式和非公平模式,区别就在于一个hasQueuedPredecessors函数,该函数用于判断是否已有节点在等待资源了并且不是该线程等待的,附上代码
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
以上就是公平模式和非公平模式实现,都是实现了AbstractQueuedSynchronizer 的tryAcquire和tryRelease方法,用于判断是否能够获取资源和释放资源,实现简单。
ReentrantLock的方法就不介绍了,都是调sync实现的方法,ReentrantLock最重要实现就是实现AbstractQueuedSynchronizer 的tryAcquire和tryRelease方法,支持可重入,还有支持Condition等待通知实现。