zoukankan      html  css  js  c++  java
  • Java可重入锁如何避免死锁

      本文由https://bbs.csdn.net/topics/390939500https://zhidao.baidu.com/question/1946051090515119908.html启发而来。

      看到一个问题,Java的可重入锁为什么可以防止死锁呢?网上看了看资料,虽然有答案说出了正确答案,但是分析的不够详细,对初学者不够友好。这里我再做一个更清晰的分析。

      首先是示例代码:

     1 public class Widget {
     2     public synchronized void doSomething(){
     3         // do something
     4     }
     5 }
     6 public class LoggingWidget extends Widget {
     7     public synchronized void doSomething() {
     8         super.doSomething();
     9     }
    10 }

       这是《java并发编程实例》一书中的例子,并且书中说:“如果synchronized 不是可重入锁,那么LoggingWidget 的super.dosomething();无法获得Widget对象的锁,因为会死锁。”

      

      乍一看好像不是这么回事,就算synchronized 不是可重入锁,可是synchronized 关键字一个在父类Widget 的方法上,另一个在子类LoggingWidget 的方法上,怎么会有死锁产生呢。

      这里其实牵涉到了Java的重写。我们看子类LoggingWidget 的doSomething方法,重写了父类Widget 的doSomething方法,但是子类对象如果要调用父类的doSomething方法,那么就需要用到super关键字了。因为实例方法的调用是Java虚拟机在运行时动态绑定的,子类LoggingWidget 的对象调用doSomething方法,一定是绑定到子类自身的doSomething方法,必须用super关键字告诉虚拟机,这里要调用的是父类的doSomething方法。

      实际上,如果我们分析运行时的LoggingWidget 类,那我们看到的应该是这样子的(这里只是为了分析,真实情况肯定和下面的例子不同):

    1 public class LoggingWidget extends Widget {
    2     public synchronized void Widget.doSomething() {
    3         // do something
    4     }   // 父类的doSomething方法
    5 
    6     public synchronized void doSomething() {
    7         super.doSomething();
    8     }
    9 }

      子类对象,其实是持有父类Widget 的doSomething方法的,只需要使用super关键字告诉虚拟机要运行的是父类的doSomething方法,虚拟机会去调用子类对象中的父类Widget 的doSomething方法的。所以,super关键字并没有新建一个父类的对象,比如说widget,然后再去调用widget.doSomething方法,实际上调用父类doSomething方法的还是我们的子类对象。

      那么这样就很好理解了,如果一个线程有子类对象的引用loggingWidget,然后调用loggingWidget.doSomething方法的时候,会请求子类对象loggingWidget 的对象锁;又因为loggingWidget 的doSomething方法中调用的父类的doSomething方法,实际上还是要请求子类对象loggingWidget 的对象锁,那么如果synchronized 关键字不是个可重入锁的话,就会在子类对象持有的父类doSomething方法上产生死锁了。正因为synchronized 关键字的可重入锁,当前线程因为已经持有了子类对象loggingWidget 的对象锁,后面再遇到请求loggingWidget 的对象锁就可以畅通无阻地执行同步方法了。

      更进一步,将上面的示例代码改写一下,那么就算synchronized 不是可重入锁,也不会产生死锁的问题了。代码如下:

     1 public class Widget {
     2     public synchronized void doSomething(){
     3         // do something
     4     }
     5 }
     6 public class LoggingWidget extends Widget {
     7     public synchronized void doSomething() {
     8         Widget widget = new Widget();
     9         widget.doSomething();
    10     }
    11 }

      在子类的doSomething方法中,直接新建了一个父类的对象widget,然后用这个父类对象来调用父类的doSomething方法,实际上请求的是这个父类对象widget的对象锁,就不涉及到可重入锁的问题了。

  • 相关阅读:
    CentOS 6.4下Squid代理服务器的安装与配置
    从C++到objectivec[转]
    在Objectivec里面使用property教程【转】
    Socket常用的数据结构【转】
    iOS 5 Storyboard 学习之 Tabbar Controller,Navigation Controller (1)
    Linux Socket编程(不限Linux)
    重要的套接字函数[转]
    HTTP,TCP/IP
    网络编程socket之bind函数[转]
    linux 下遍历目录中的目录项
  • 原文地址:https://www.cnblogs.com/noodleprince/p/8722356.html
Copyright © 2011-2022 走看看