版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)
在《Java并发编程实战》的2.3.2重入章节中提到了“由于Widget和LoggingWidget中的doSomething方法都是synchronized方法,因此每个doSomething方法在执行前都会获取Widget上的锁。 ”那么问题就来了,为何每个doSomething方法都会需要获取Widget的锁呢?
public class Widget {
public synchronized void doSomething(){
//...
}
}
class LoggingWidget extends Widget{
public synchronized void doSomething(){
System.out.println(toString()+":calling doSomething");
super.doSomething();
}
}
调用子类LoggingWidget类构造方法的时候,只会构造子类对象,其中包含来自父类的域。由于父类和子类中都有syunchronized修饰的方法,所以进行分步骤(时间上)调用这俩方法,即一个进程调用自己所持有的锁,这个时候就引起了内置锁的重入机制。 至于为何每个doSomething方法都会需要获取子类对象LoggingWidget的锁,它的解释是由于至始至终只创建了一个对象,锁即对象,相同对象对应相同锁,相同锁的同一进程重复访问需要重入机制。
https://www.zhihu.com/question/51920553/answer/128761716 https://www.zhihu.com/question/28113814 https://stackoverflow.com/questions/27900332/reentrant-lock-java-concurrency-in-practice https://ask.csdn.net/questions/768807
《Java并发编程实战》重入小节中对于锁的归属问题并没有写正确,实际上调用子类doSometing方法时,请求的锁都是子类对象LoggingWidget的锁,并非是父类对象的锁,一个有力的辩驳理由是:父类对象从始至终没有被创建,JVM中只有子类对象。 对于这个问题,我们可以以两个方面理解。一方面,书本上写到:“每次获取的是子类Widget对象的锁”这句话一方面可以认为其说得不够明确,是错误的。另一方面,由于Java鼎鼎有名的多态性质,那么在许多代码中子类对象和父类对象的确没有必要去细分,所以也可以认为此处说法没有错误。