重入锁
支持公平锁与非公平锁,在构造函数中体现,默认是非公平锁。
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 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();
}
重入锁可以实现任意线程在获取到锁之后能够再次获取到锁,而且不会被阻塞,需要解决两个问题:
(1)线程再次获取锁
锁需要去识别获取所得线程是否为当前占据锁的线程,如果是,则再次获取成功,如果不是,则获取失败。
(2)锁的最终释放
所在每次成功获取锁之后,获取次数自增,每次释放锁时,次数自减,当次数为0时,才算最终成功释放锁。而在前面释放过程都返回false。
ReentrantLock是通过组合自定义同步器来实现所的获取与释放过程。以下是非公平性获取锁的JDK源码:
/**
* 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)) { //如果是第一次获取该锁,则通过CAS操作后获取成功。
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;
}
成功获取锁的线程再次获取锁,知识增加了同步状态值。以下是释放同步状态时减少同步状态值:
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); // 将当前占据锁的线程设置为null
}
setState(c);
return free; //如果该锁被获得n次,那么在前n-1次释放时均返回false,最后一次返回true。
}
公平锁相比于非公平锁,其开销较小,非公平锁线程间切换次数少。公平锁保证了FIFO原则,代价是进行了大量的线程切换,非公平锁可能造成线程“饥饿”,但极少的线程切换保证了更大的吞吐量。
而对于公平锁,那么所得获取按照FIFO顺序,源码如下:
/**
* 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)) { //hasQueuedPredecessors()判断当前节点是否有前驱节点,如果有返回true,
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;
}
}