我有一个案例,其中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;
}
感谢您的任何建议。
劳伦斯
答案 0 :(得分:3)
你没有必须同步它,因为它已经在超类中同步,并且没有其他调用,但你应该。您对createBitmap()
的实现依赖于超类的实现细节。
在您访问共享字段的每个点都进行同步。
由于这个事实,您当前的子类'代码非常容易出错!
虽然在this
上进行同步是值得怀疑的,但是通过其他人无法访问的私有对象进行同步是一个更好的主意。因此,使用类对象并在其上进行同步的客户端无法破坏您的代码。
答案 1 :(得分:1)
这不是关于“锁定”变量:你不能这样做。你的代码中有一个正确的锁。但是,“线程安全”是指“任何合理使用都是安全的”。由于您更改outBmpB
的方法是protected
- 即包成员和所有孩子都可以使用 - 您最好明确同步。
作为一般规则,每次访问共享可变状态时,都必须确保持有锁。在你的情况下,你不确定。同时,Java锁是可重入的,因此嵌套同步不会受到伤害 - 并且可能会让您免于意外。
答案 2 :(得分:-1)
作为一般概念,最好锁定您正在使用的对象(在您的情况下为bmpA
和outBmpB
)而不是容器对象,除非您确实需要这样做(并且那种情况下同步方法会更好。)
根据您的具体情况,synchronized (this)
区块会相互排斥,所以是的,如果您不在其他任何地方拨打createBitmap()
,它将会起作用在createBitmap()
内进行同步比在run()
内进行同步要好得多。