笔记 - 关于继承与可重入锁

继承与可重入锁

可重入锁在继承情况下super锁住的是谁。关于这个问题,设计了一个Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 父类
public class Widget {
public synchronized void doSomething() {
...
}
}

// 子类
public class LoggingWidget extends Widget {

@Override
public synchronized void doSomething() {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}

如果上面代码似曾相识,好像在哪里见过,不用怀疑,我就是从《Java并发编程实战》里摘下来的。至于为什么呢?因为我对里面有些地方表示疑惑。

问:子类重写了父类的doSomething方法,然后通过super去调用父类的doSomething方法,那么在父类同步锁的doSomething方法里锁住的是谁?是父类Widget吗,还是子类LoggingWidget?

为此,通过Demo来说话吧

Demo

尝试直接在父类同步方法里打印

对比代码

对比代码:

对比代码

这里先直接new一个父类去调用他的方法,来看看父类方法中的this(即锁的是什么)

代码结果:

对比代码结果

我们可以看到直接调用父类方法,不出意外都是会打印出自个儿的类的地址。那么下面我们看看通过super去调用又会怎样。

实验代码

实验代码:

第一个demo

运行结果:

第一个Demo运行结果

从结果可以看出 先打印 “子类 - doSomething” 再打印 “父类 - doSomething” 最后打印出锁住的对象 “thread.LoggingWidget@74a14482”。这里打印出的是子类的地址。对比我们的对比代码中的结果,我们可以很轻易地得出 在一个得到了锁的方法里通过使用super去调用父类的同步方法,那么父类同步方法中被锁住的是子类对象,其父类并没有被锁住

结论

在《Java并发编程实战》里关于重入锁的描述中有个不那么严谨的说法:由于Widget和LoggingWidget中doSometimes方法都是Synchronized方法,因此每个doSomething方法在执行前都会获取Widget上的锁。关于这个,通过一些简单的Demo,现在知道,调用一个Synchronized方法,Synchronized锁住的是调用的对象(即子类),而在这个Synchronized方法里通过super调用父类的同步方法,父类同步方法锁住的也是子类对象

-------------本文结束感谢您的阅读-------------