前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java并发编程实战-内置锁不是重入的,那么这段代码将发生死锁-以及书籍勘误

Java并发编程实战-内置锁不是重入的,那么这段代码将发生死锁-以及书籍勘误

作者头像
Fisherman渔夫
发布2019-07-31 15:01:51
7150
发布2019-07-31 15:01:51
举报
文章被收录于专栏:渔夫渔夫
知识共享许可协议
知识共享许可协议

版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

引出:

在《Java并发编程实战》的2.3.2重入章节中提到了“由于Widget和LoggingWidget中的doSomething方法都是synchronized方法,因此每个doSomething方法在执行前都会获取Widget上的锁。 ”那么问题就来了,为何每个doSomething方法都会需要获取Widget的锁呢?

代码:

代码语言:javascript
复制
public class Widget {
public synchronized void doSomething(){
    //...
}
}

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

重入问题的解决

  1. 首先这个问题涉及了Java中的继承以及Super关键字的语法,必须把握住这一中心要点,才能理解这个问题。我们可以这样认为,子类继承父类,并调用子类构造器新建子类对象时,会在内存空间里开辟子类对象自身的实例域以及从父类继承过来的实例域,但他们都属于子类对象所管理的域,并不会创建额外的空间来存储父类对象的实例域。其次,从父类继承过来的实例域是通过调用子类构造器过程中的调用(编译器默认自动进行的,不用显示写出)的父类构造器所创建的。
  2. 遇到new关键字,JVM分步的实现方式: 1)先分配空间(父类中的实例变量和子类中的实例变量,注意先后顺序) 2)初始化默认值 3) 调用当前类的 < init >(注意<init的结构)
  3. 在《Java并发编程实战》中的同步代码块(方法)锁的定义为:方法调用所在的对象,这就意味着——是否要考虑重入要依据是否是同一锁也就是同一个对象的访问。然而,由1和2可以推出一点,创建子类对象的时候并未创建父类对象,也就是说对于同名的doSomething()方法,子类对象中有俩,且都是用synchronized修饰,只不过一个是子类对于父类的继承以及重写,用this来修饰;另一个是继承来自于父类(未重写),用super来区分。
  4. 1到3点我们可以推出应当把子类的doSomething()方法和父类的super.doSomething()方法看作同一对象的不同方法(前者使用this关键字且默认省去,后者则用了super关键字且不能省略),且都是被synchronized修饰。由于锁即对象,所以重入又可以看作是关于同一对象中访问不同synchronized修饰的方法问题。

总结

调用子类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鼎鼎有名的多态性质,那么在许多代码中子类对象和父类对象的确没有必要去细分,所以也可以认为此处说法没有错误。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年07月10日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引出:
  • 代码:
  • 重入问题的解决
  • 总结
  • 参考网址
  • 补充
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档