Java并发编程实战重入锁(子类同步方法调用父类的同步方法)
看如下代码
public class Widget { public synchronized void doSomething () { System.out.println(this.toString()+"---------------------"); } }
public class LoggingWidget extends Widget { public synchronized void doSomething () { System.out.println(this.toString()+ ": calling doSomething"); super.doSomething(); } public static void main (String[] args) throws InterruptedException { for (int i = 0; i < 2; i++) { Thread thread = new Thread(() -> { Widget widget = new LoggingWidget(); widget.doSomething(); }); thread.start(); } } }
- 书上说如果内置锁不是可重入的,那么这段代码将发生死锁.我们先来理解一下什么是重入锁,当某个线程请求一个由某个线程持有的锁时,发出的请求就会阻塞.然而,由于内置锁时可重入的,因此如果某个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功.
- 理解了重入锁,我们来看下几种synchronized的锁对象,同步方法的锁对象:this,静态的锁对象:当前类的class对象,同步代码块的锁对象:任意对象.
- 接下来我们来分析下代码的执行,假设线程A初始化了LoggingWidget 对象,接着去执行doSomething 方法,由于doSomething 方法是非静态同步方法,所以锁对象就是this对象本身,获取对象锁,然后打印this.toString,接着调用super.doSomething 方法,由于是同步方法所以也需要获取锁对象,由于线程A已经获取了对象锁,所以super.doSomething方法如果和doSomething 方法是同一个锁对象就可以执行,如果不是就获取不到锁,就会产生死锁,永远获取不到.笔者在这里不理解的问题是super.doSomething()是谁调用的,如果父类,那么这个同步方法的锁对象就是父类本身,那么线程A不可能同时获取两个锁对象.如果是子类调用的线程A已经获取了锁对象,所以就可以执行.
- 我们来看下运行结果:
com.concyrrency.test.lock.LoggingWidget@2cb7a5c1: calling doSomething com.concyrrency.test.lock.LoggingWidget@2cb7a5c1--------------------- com.concyrrency.test.lock.LoggingWidget@77df833b: calling doSomething com.concyrrency.test.lock.LoggingWidget@77df833b---------------------
- 可以看到两个线程的分别打印的this.toString都是一样的,说明super.doSomething()的调用者是子类,而且内置锁是可以重入的.
- 理解super关键字,在Java类中使用supper来引用分类的成分,用this来引用当前的对象,如果一个类从另一个类继承,new这个子类实例对象的时候,这个子类对象会含有一个父类对象,怎么去引用父类的对象了,使用super来停用,this指的是当前对象的引用,super是当前对象里面父类的引用.
名称栏目:Java并发编程实战重入锁(子类同步方法调用父类的同步方法)
网页地址:http://scgulin.cn/article/pecdpp.html