- 实现了Lock接口
- 独占锁 state表示资源的状态,
state = 0 表示没有被占用
state >= 1表示资源被占用,当一个线程重复在相同的锁上加锁那么就会对state执行 state++ - 通过内部类AQS实现加锁以及释放锁的操作 tryAcquire(int),tryRelease
- 通过三个内部类来实现独占锁操作
Sync:作为公平锁 fair 和非公平锁 nonfair的父类,实现了nonfairTryAcquire和tryRelease方法
NonfairSync:非公平获取锁,在一个线程释放锁的时候会发生插队
FairSync: 公平锁,按照排队的顺序获取锁
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}}
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
//公平锁和不公平锁需要实现的加锁方式
abstract void lock();
/**
* 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;
}
}
//当前线程已将持有锁,那么将state + 1 返回
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 0->1->2那么需要进行同等数量的释放锁操作 2->1->0
protected final boolean tryRelease(int releases) {
int c = getState() - releases;//将原有的state - 1
//检查当前线程是不是持有锁的线程
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {//锁已经被释放,对持有的线程信息进行清理
free = true;
setExclusiveOwnerThread(null);
}
//最后设置锁状态
setState(c);
return free;
}
//是否是独占模式
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
非公平锁 NonfairSync
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);
}
}
公平锁
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;
}
}
//当前线程持有锁那么就对状态进行+1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
总结
ReentrantLock 是通过独占的方式进行加锁,提供了公平锁和肺公平锁两种获取锁的方式
1.通过state来表示资源的获取,当同一个线程重入锁的时候会将state进行+1 ,释放所得时候每次进行-1,需要释放的次数需要和加锁的次数相同
2 公平锁和非公平锁的实现区别就是就是非公平锁在获取所得方式会直接尝试通过CAS设置state的状态抢占锁,而公平锁不会