锁的重入是指同一个线程可以多次获取同一个锁,synchronize 是隐式的可重入锁,ReentrantLock 通过代码实现了锁的重入:
final boolean nofairTryAcquire(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) throw new Error(“Maximum lock count exceeded”);
setState(nextc);
return true;
}
return false;
}
从上面的代码中,可以一目了然的发现,当获取锁的线程与拥有锁的线程是同一个线程时,仅会对状态进行累加。so easy , 并没有什么难度。那接下来我们想一下,如何实现公平所和非公平锁,上面的代码是非公平锁的实现方式。那如何实现公平锁那?所谓的公平锁就是所有获取锁的线程都要按照“先来后到”的顺序获取锁。假设线程 B 在阻塞队列中,等待获取锁,如果还有一个线程 A 在 B 的前面,那么 B 就要让 A 先获取锁。因此在 B 尝试获取锁之前,只要判断一下它是否还有前驱的队列即可。很 easy 吧:
final boolean fairTryAcquire(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;
}
公平所和非公平锁的各自优势是什么那?公平锁很好理解,可以防止出现线程饥饿现象,每一个线程都有机会获取到锁。非公平锁可能会导致线程饥饿,但是我们一般使用非公平锁,因为非公平锁可以减少上下文的切换,提高效率。