我最近在Joshua Bloch的一本书中发现了一个代码示例“有效的java”
示例如下所示:
abstract class AbstractFoo {
private int x;
private int y;
private final AtomicReference<State> state = new AtomicReference<>();
private static enum State {
NEW, INITIALIZING, INITIALIZED;
}
public AbstractFoo() {
}
protected AbstractFoo(int x, int y) {
initialize(x, y);
}
protected void initialize(int x, int y) {
if (!state.compareAndSet(State.NEW, State.INITIALIZING)) {
throw new IllegalStateException("Already initialized");
}
this.x = x;
this.y = y;
state.set(State.INITIALIZED);
}
private void checkInit() {
if (state.get() != State.INITIALIZED) {
throw new IllegalStateException("Uninitialized");
}
}
public int getX() {
checkInit();
return x;
}
public int getY() {
checkInit();
return y;
}
}
这里是抽象类,用于继承而不是可序列化的,我有一个可序列化的子类,看起来像这样
static class Foo extends AbstractFoo implements Serializable {
private static final long serialVersionUID = 5265405733720299160L;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
int x = in.readInt();
int y = in.readInt();
initialize(x, y);
}
private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
out.writeInt(getX());
out.writeInt(getY());
}
public Foo(int x, int y){
super(x, y);
}
}
主要问题与此方法有关
protected void initialize(int x, int y) {
if (!state.compareAndSet(State.NEW, State.INITIALIZING)) {
throw new IllegalStateException("Already initialized");
}
this.x = x;
this.y = y;
state.set(State.INITIALIZED);
}
如果我删除CAS检查并直接输入值会出现什么问题,我真的不明白为什么这个检查可能是必要的
答案 0 :(得分:0)
此检查是必要的,因为否则可以多次初始化对象。您可以轻松检查:
public Foo() {
this.initialize(2,3);
this.initialize(3,4);
}
然后删除该检查,看看会发生什么。
另请注意,这不仅仅是一项检查 - 它也是一组(check)。这意味着如果对象实际上尚未初始化(State.NEW
),那么compareAndSet
将返回true
并将状态更改为State.INITIALIZING
。正如您所看到的,这种状态只会持续一段时间来设置两个变量,然后更改为State.INITIALIZED
- 这是为了线程安全初始化,因为state
是AtomicReference