什么是可重入
一个线程在执行代码时获取锁之后,如果再继续运行时又遇到同一把锁则能自动获取。
synchronized如何实现可重入
为每个锁关联一个获取计数值和一个所有者线程。当计数值为0时,这个锁就被认为是没有被任何线程持有。当线程请求一个未被持有的锁时,JVM将记下锁的持有者,并且将获取计数值置为1.如果同一个线程再次获取这个锁,计数值将递增,而当线程退出同步代码块时,计数器将会减一。当计数值为0时,这个锁将会被释放。
Lock如何实现可重入
ReentrantLock通过Sync实现锁,而Sync继承了AbstractQueuedSynchronizer。在AbstractQueuedSynchronizer中存在一个state变量,state最初为0说明此时没有线程持有锁,当有线程开始竞争时,他们通过CAS将state修改为1,谁修改成功,谁便获取了锁,并且会将该线程记录到exclusiveOwnerThread中,该变量在AbstractOwnableSynchronizer中,AbstractOwnableSynchronizer是AbstractQueuedSynchronizer的父类。exclusiveOwnerThread变量也帮助实现了可重入,如果当前线程==exclusiveOwnerThread说明当前线程已经持有锁,那么只有增加state的计数即可
final boolean initialTryLock() {
Thread current = Thread.currentThread();
if (compareAndSetState(0, 1)) { // first attempt is unguarded
setExclusiveOwnerThread(current);
return true;
} else if (getExclusiveOwnerThread() == current) {
int c = getState() + 1;
if (c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
} else
return false;
}