线程安全实例化父类,在反序列化子项期间

时间:2018-02-01 14:24:21

标签: java multithreading serialization

我最近在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检查并直接输入值会出现什么问题,我真的不明白为什么这个检查可能是必要的

1 个答案:

答案 0 :(得分:0)

此检查是必要的,因为否则可以多次初始化对象。您可以轻松检查:

public Foo() {
  this.initialize(2,3);
  this.initialize(3,4);
}

然后删除该检查,看看会发生什么。

另请注意,这不仅仅是一项检查 - 它也是一组(check)。这意味着如果对象实际上尚未初始化(State.NEW),那么compareAndSet将返回true并将状态更改为State.INITIALIZING。正如您所看到的,这种状态只会持续一段时间来设置两个变量,然后更改为State.INITIALIZED - 这是为了线程安全初始化,因为stateAtomicReference