日期:2014-05-20  浏览次数:20666 次

关于一个线程同步的问题.....
在看java并发编程实战中,碰到的一个重入问题,说是子类的同步方法调用父类的同步方法时,使用的是一个锁,我做了下面的测试,发现锁确实是子类,但是我不明白为什么会这样。。。毕竟是2个类,我一直觉得不同的类,他的方法锁是当前类的对象,这里怎么不同的类,锁却是一样的?请高手赐教!!

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class ParentWidget
{
public  void doSomething() 
{  
synchronized(this)
{
System.out.println("父类加锁对象");
System.out.println(this.hashCode());
}
    }
}

class LoggingWidget extends ParentWidget
{
public  void doSomething() 
{  
synchronized(this)
{
System.out.println("子类加锁对象");
System.out.println(this.hashCode());
super.doSomething();
}
    }
}

class MyThread extends Thread
{
private LoggingWidget lw;

public MyThread(LoggingWidget lw)
{
 this.lw=lw;
}

@Override
public void run()
{
this.lw.doSomething();
}
}


public class Widget
{
public static void main(String[] str)
{
LoggingWidget lw=new LoggingWidget();
ExecutorService pool = Executors.newCachedThreadPool(); 
for(int i=0;i<3;i++)
{
MyThread tmp=new MyThread(lw);
pool.execute(tmp);
}
}
}

------解决方案--------------------
这个问题我来解答吧,LZ看书很仔细,我以前也没注意过这个问题,专门查了一下。
首先思路是这样:
编译synchronized的时候,会形成一个start-end代码块对一个reference指针进行加锁操作,LZ代码里的锁是对象锁,换句话说,是对对象本身进行加锁,这里没有问题,引发歧义的是子类调用了父类方法,父类方法也有一把锁,这把锁锁的和子类里锁的是不是同一个对象。

答案是,锁的是同一个对象,所以重入锁这个概念到此解释完毕没有问题。接下来,为什么是同一把锁呢?这里要关注JAVA处理继承关系时内存分配问题,简单的说,实例化一个子类的过程中有几个对象。答案是1个,内存会为子类对象来分配内存空间,也就是只有子类一个对象。那么父类的域是如何访问的?答案是,父类被加载了,但是没有被实例化,JVM为子类分配内存空间的时候,也会有一个内存块为存放父类的域,这个内存块用super指针来引用。到此解释完毕,结论:只有一个对象,也只有一把锁,锁对于线程而言可重入。