java中有两种锁:内置锁和显示锁。内置锁是JVM管理的锁,由synchronized关键字开启,但是它是一个非公平锁。显示锁是可以由java程序员自己控制的锁像本次要介绍的可重入锁:ReentrantLock,它可以设置成一个公平锁。具体原来如何,最近看了下源码,顺便记录下源码所得。
先简单介绍下显示锁的代码结构,ReentrantLock(后面简称RL)内部维护了一个内部类:Sync,源码见下面的
abstract static class Sync extends AbstractQueuedSynchronizer {
.......
.......
}
内部类Sync 继承的 AbstractQueuedSynchronizer 就是我们平常经常说到的AQS。AQS 源码太多,这里就不贴了,简单来说就是,它维护了一个双向链表在其内部,这个链表有什么用?到时候下面讲公平锁的实现时在会知道。这里放下双向链表的源码:
static final class Node {
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
Sync有什么用?来看下RL的加锁和解锁方法:
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
public void lock() {
sync.lock();
}
public void unlock() {
sync.release(1);
}
}
由上面源码可知,RL的加锁和解锁实际上调用的都是Sync的加锁和解锁方法。但是,Sync 是抽象类,那他必然有实现类,没错,在RL里,Sync有两个实现类:
NonfairSync,FairSync。
非公平锁,RL默认构造的是非公平锁
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
NonfairSync的实现原理是通过java的CAS去获取锁,如何获取不到就会放到双向链表里,下面是它的源码:
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
/**
* 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);
}
}
/**
* 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;
}
公平锁,通过构造函数指定构建公平锁:
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
和非公平锁类似,也是通过java的CAS去完成加锁,不同的是,公平锁每次获取锁的线程都会拿链表头的线程优先获取锁,两种锁tryAcquire方法的不同完成不同的加锁方式。下面是源码:
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
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;
}
}
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());
}
通过研究tryAcquire方法我们可以看到,RL的锁状态是通过其内部的一个volatile 修饰的state参数进行标志的,当通一个线程多次调用tryAcquire 方法,state会加上acquires(RL中是1),解锁的时候会减去acquires,加了几次锁,在释放的时候就要减去几次,这就是RL的可重入锁的由来。
/**
* 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;
}
/**
* 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;
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
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;
}