Are inherited non-final fields visible to other threads?
Consider a third-party class like
class A {
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
which I make immutable like
final class ImmutableA extends A {
public ImmutableA(int value) {
super.setValue(value);
}
public void setValue(int value) {
throw new UnsupportedOperationException();
}
}
The visibility guarantee for final fields doesn't apply here. My question is if other threads are guaranteed to see the correct state of ImmutableA
.
I开发者_开发技巧f not, is there a solution? Using delegation is not an option since I need ImmutableA
to be an A
.
yes, if you use volatile
this has the guarantee that writes to it are visible to other threads
class A {
private volatile int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
You could use synchronized
, though this may slow down the getter:
final class ImmutableA extends A
{
public ImmutableA(int value) {
synchronized (this) {
super.setValue(value);
}
}
public void setValue(int value) {
throw new UnsupportedOperationException();
}
public synchronized int getValue() {
return super.getValue();
}
}
Inspired by starblue's answer I've found a solution using no synchronization. It combines delegation with inheritance:
final class ImmutableA extends A {
private final ImmutableA that;
public ImmutableA(int value) {
super.setValue(value);
that = this;
}
public void setValue(int value) {
throw new UnsupportedOperationException();
}
private int superGetValue() {
return super.getValue();
}
public int getValue() {
return that.superGetValue();
}
}
I think it should work because of the final
visibility guarantee. But I don't think it's worth the hassle. All methods need to be overridden and duplicated, since that.getValue() would lead to infinite recursion, and that.super.getValue()
(or super.that.getValue()
) is illegal.
精彩评论