This is a successor of my previous question, Is this variable being safely accessed by using synchronization?
For the following program,
Class SubClassB extends SuperClassA {
protected int c;
public void inc() {
synchronized (this) {
c++;
}
}
public void dec() {
synchronized ( (SuperClassA) this) {
c--;
}
}
}
Would the counter “c” be accessed thread safe ? I am not sure that in the “dec()” method, is the SuperClassA cast “this” reference a valid object for the synchronized block ? If yes, would the two synchronized blocks lock the same “this” object ? (As it seems to me that “(SuperClassA) this” is not equal to “this”)
This strange simulated code comes from the following real life example where SuperClassA is a base class that is not supposed to be modified,
Class SuperClassA {
protected int c;
public void dec() {
synchronized (this) {
c--;
}
}
}
Class SubClassB extends SuperClassA {
public void inc() {
synchronized (this) {
c++;
}
}
public void dec() {
super.dec();
}
}
In this example, the “dec()” method in SubClassB calls its superclass’s “dec()” method which performs a lock to a “this” object that I suppose to be “SuperClassA.this”. If the locked object in SubClassB’s “inc()” method is not exactly the same as the locked object in SubClassB’s “dec()” method, then I am wondering the inherited counter “c” in SubClassB may NOT be safely accessed by different threads. I feel that there is some ambiguities in using the “this” reference in synchronized blocks.
In the real life example, if I want SubClassB’s counter “c” to be thread safe, do I need to add one more synchronized block in its “dec()” method, like this,
Class SubClassB extends SuperClassA {
public void inc() {
synchronized (this) {
c++;
}
}
public void dec() {
synchronized (this) {
super.dec();
}
}
}
But it seems that such added block is not elegant and may be redundant !
Does anyone have some ideas on these questions. Thanks in advance.
Lawrence
Yes, it’s using the same lock object.
Yes.
Yes. Even if you cast the instance to something it can be casted to (even Object), it’ll still refer to the same object.
It is redundant. Extra synchronization is required only if you call multiple synchronized methods and the combined effect must be atomic.