【Lock】锁的可重入性(Reentrancy)

Posted by 西维蜀黍 on 2019-02-25, Last Modified on 2021-09-21

可重入性(Reentrant Lock)

Java 中的固有锁(intrinsic lock)具有可重入性(Reentrancy),这意味着锁的获取是以每个线程(per-thread)为单位的,而不是每个调用(per-invocation)。

可重入性通过为每个锁关联一个占用计数和当前拥有进程。当计数为 0 时,锁未被持有。

当一个线程获得了一个未被持有的锁时,JVM 会记录锁当前的主人为这个线程,并且将锁的计数+1。

当同样的线程再次申请获得锁时,锁计数会再+1。而当拥有锁的线程退出 synchronized 块时,锁计数-1。最终,当锁计数到达 0 时,锁被释放。


锁的可重入性避免了在某种情况下的死锁(deadlock)。

public class Widget { 
	public synchronized void doSomething() { 
		...
	} 
}

public class LoggingWidget extends Widget { 
	public synchronized void doSomething() { 		
		System.out.println(toString() + ": calling doSomething"); 
		super.doSomething(); 
	} 
}

比如,在上面例子中,在一个 synchronized 方法中又调用了另一个 synchronized 方法。如果固有锁不具有可重性,super.doSomething(); 的调用永远不会进入,因为在调用 LoggingWidget 对象的 doSomething() 时,LoggingWidget 类占用锁,因而 LoggingWidget 类的子类 Widget 类无法占用锁, 最终无法进入 Widget 类的 doSomethings()。本质是因为产生了死锁。