这取自Joshua Bloch撰写的一本书。
我不是英语母语人士,因此有理由要求澄清疑问。
因为内部锁是可重入的,所以如果线程尝试 获取它已经拥有的锁,请求 成功。可重入意味着在a上获取锁 每线程而不是**每次调用。
基于每次调用,他是否意味着在每个方法调用? 考虑一下代码段:
class Factoriser{
public synchronized void doSomething(){
// code goes here
}
}
假设有一个线程A,并且能够获取具有实例方法doSomething()的对象的锁定。由于某种原因,相同的线程线程A再次获取对同一对象实例方法doSomething()的锁定(想象一下,之前的锁还没有被释放)。
如果我正确理解了约书亚的陈述,那么即使有2个方法调用/调用,也只会有一个锁。我的理解是100%正确的。请举例说明。我很困惑,因为作者在下面的段落中澄清了这一点,这进一步困扰了我。
通过将每个锁与获取计数和拥有线程相关联来实现可重入性。当计数为零时,锁定被视为未被保留。当线程获取以前未保留的锁时,JVM会记录所有者 并将采集计数设置为1。如果那个线程相同 再次获取锁定,计数递增,并且 当拥有的线程退出同步块时, 计数递减。当计数达到零时,锁定被释放。
如果Reentrancy / locks获取不是基于每次调用,为什么JVM为我上面描述的场景设置的计数设置为2?
答案 0 :(得分:2)
计数器用于匹配锁定加料和粪便。仅当计数器为0时才能释放锁定。将方法foo()
标记为synchronized
并在对象obj
上调用它与以下块相同:
// calling obj.foo()
synchronized(obj) {
// Do the foo-work
}
假设我们有两个同步方法:foo()
和bar()
,后者从前者调用。调用将具有以下结构:
final FooBar obj = new FooBar();
// calling obj.foo()
synchronized(obj) { // 1. here the lock is acquired, the counter is set to 1
// do some foo-work
// calling obj.bar()
synchronized(obj) { // 2. the same lock object, the counter is set to 2
// do the bar-work
} // 3. the counter is set to 1, the lock is still not released
// continue doing the foo-work
} // 4. the counter is 0, the lock is released
如果没有计数器,在步骤3我们将释放锁定,这将是一个错误,因为我们仍在外部同步块中。因此,需要计数器才能正确实现重入。