通过介绍ReentrantLock中的3个内部类,分别是Sync、FairSync和NonfairSync;其中后面的两者继承前面的Sync,同时Sync是一个独占锁(exclusive)下;我们通过分析tryAcquire,tryRelease的源码来分析ReentrantLock的实现
FairSync和NonfairSync的独占功能实现
- 公平锁(FairSync):每个线程抢占锁的顺序为先后调用lock方法的顺序依次获取锁;tryAcquire的具体实现如下:
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) {
// /如果队列中没有其他线程 说明没有线程正在占有锁!且当前的state为o;这个是和nonfairsync的区别
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//如果不为0 意味着,锁已经被拿走了,但是,因为ReentrantLock是可重入锁,
//是可以重复lock,unlock的,只要成对出现行。一次。这里还要再判断一次 获取锁的线程是不是当前请求锁的线程。
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- 非公平锁(NonfairSync):每个线程抢占锁的顺序不定,谁运气好,谁就获取到锁,和调用lock方法的先后顺序无关,类似于堵车时,加塞的那些XXXX。具体源码实现如下
/**
* 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);
}
/**
* 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) {
//注意下:不断地尝试修改state状态,
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;
}
公平锁和非公平锁获取锁的区别
- 公平锁: 首先先读取状态位state,然后再做判断,之后使用cas设置状态位。能获取锁的线程就获取锁,不能获取锁的线程被挂起进入队列。之后再来的线程的等待时间没有已经在队列里的线程等待时间长,所以会一直进入等待队列。 公平锁类似于排队买火车票一样,后面来的人没有前面来的人等待时间长,会一直在队尾被加入到队列里。需要判断队列中有没有被其他线程占有~~
- 非公平锁:尝试通过使用CAS判断设置状态位,是一种抢占式的方式。同时非公平锁也没有等待时间长的线程会优先获取锁这个概念。非公平锁类似吃饭排队,但是总会有那么几个人试图插队。
锁的释放
- 两种锁都继承父类的Sync的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;
}
参考地址:
JDK1.8 AbstractQueuedSynchronizer的实现分析(上)http://www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizer
Java可重入锁ReentrantLock分析 https://fangjian0423.github.io/2016/03/19/java-ReentrantLock-analysis/
网友评论