是否可以使用同步安全地访问此变量?

时间:2012-01-04 13:17:02

标签: java nested synchronized

我有一个案例,其中Java类有一个包含synchronized块的超类。

Class SuperClassA {
     private Bitmap bmpA;

     protected abstract Bitmap createBitmap();

     public void run() {
          synchronized (this) {
               bmpA = createBitmap();
          }
     }

     // some other codes.
}

Class SubClassB extends SuperClassA {
     private Bitmap outBmpB;

     protected Bitmap createBitmap() {
          outBmpB = ..... // create and process "outBmpB".

          Bitmap bmp;
          bmp = ..... // create and process "bmp".
          return bmp;
     }

     public Bitmap getOutBmpB() {
          Bitmap tempBmp;
          synchronized (this) {
               tempBmp = outBmpB.clone();
          }
          return tempBmp;
     }

     // some other codes.
}

B类中的“getOutBmpB()”方法由一个线程运行,而ClassB中继承的“run()”方法由另一个线程运行。在ClassB中实现的“createBitmap()”方法应该在“run()”方法内的同步块中运行。

我的问题是我不确定两个线程是否安全地访问了ClassB中新定义的类变量“outBmpB”。我不确定“run()”方法中的“synchronized(this)”块是否也会“锁定”在ClassB中定义的“outBmpB”变量?如果没有,那么我可以在“createBitmap()”实现中添加“synchronized(this)”块。 e.g。

 protected Bitmap createBitmap() {
      synchronized (this) {
           outBmpB = ..... // create and process "outBmpB".
      }

      Bitmap bmp;
      bmp = ..... // create and process "bmp".
      return bmp;
 }

感谢您的任何建议。

劳伦斯

3 个答案:

答案 0 :(得分:3)

你没有必须同步它,因为它已经在超类中同步,并且没有其他调用,但你应该。您对createBitmap()的实现依赖于超类的实现细节。 在您访问共享字段的每个点都进行同步。

由于这个事实,您当前的子类'代码非常容易出错!

虽然在this上进行同步是值得怀疑的,但是通过其他人无法访问的私有对象进行同步是一个更好的主意。因此,使用类对象并在其上进行同步的客户端无法破坏您的代码。

答案 1 :(得分:1)

这不是关于“锁定”变量:你不能这样做。你的代码中有一个正确的锁。但是,“线程安全”是指“任何合理使用都是安全的”。由于您更改outBmpB的方法是protected - 即包成员和所有孩子都可以使用 - 您最好明确同步。

作为一般规则,每次访问共享可变状态时,都必须确保持有锁。在你的情况下,你不确定。同时,Java锁是可重入的,因此嵌套同步不会受到伤害 - 并且可能会让您免于意外。

答案 2 :(得分:-1)

作为一般概念,最好锁定您正在使用的对象(在您的情况下为bmpAoutBmpB)而不是容器对象,除非您确实需要这样做(并且那种情况下同步方法会更好。)

根据您的具体情况,synchronized (this)区块会相互排斥,所以是的,如果您不在其他任何地方拨打createBitmap() ,它将会起作用createBitmap()内进行同步比在run()内进行同步要好得多。