我们知道synchronized可以加在方法上也可以加在代码块上,其实加在方法上也相当于加载代码块上,好比这种形式:
synchronized(this){
doSomething();
}
从这里可以看出,锁其实是基于对象的,是对当前访问的对象进行加锁,现在假设有如下两个类:
class Widget{
synchronized doSomething(){
.........................
}
}
class LoggingWidget extends Widget
{
@Override
synchronized doSomething(){
..................
super.doSomething();
}
}
因为锁的是基于对象的,不管父类还是子类,如果你需要调用当前的方法,那么对用户这个方法而言他对应的都是同一个对象,因为是一个对象在调用这个方法,此时this关键字指向的就是这个对象,你可以想象子类现在是这样的:
class
@Override doSomething(){LoggingWidget {
synchronized (this)
{
............//Son类doSomething()中的操作
synchronized (this)
{
............//Foo类doSomething()中的操作
}
}
}
}
想象成上面这种形式的话,可以看到,到这里该对象的锁获需要获取两次,如果锁是不可重入的,那么第二次锁将获取不到,那么这个时候就会产生死锁。对象维持一个锁的计数器,进入锁加一,退出锁减一,如果为零则可以获取该锁。
换句话说就是,LoggingWidget实例对象调用doSomething方法时此时持有的是LoggingWidget实例对象的锁,之后调用super.doSomething,这时仍然对于LoggingWidget实例对象加锁,因为此时仍然使用的是LogginWidget实例对象内存空间中的数据。这也说明了内置例对象加锁,因为此时仍然使用的是LogginWidget实例对象内存空间中的数据。这也说明了内置锁重入的重要性,若不是重入的,那么当调用super.doSomething时,因为线程已经持有了LoggingWidget实例锁,再次请求持有LoggingWidget实例锁时,就会永远等待一个获取不到的锁