Java 冰棒不可变

Bri*_*anV 5 java concurrency immutability

我正在解决一个问题,我需要为一个问题加载大量输入,并处理这些输入以创建一个“问题空间”(即构建允许有效访问输入的数据结构等)。一旦这个初始化完成,一个多线程进程就会启动,它以并发的方式广泛地使用有组织/处理过的输入。

出于性能原因,我不想在并发阶段锁定和同步所有读取操作。我真正想要的是一个不可变的对象,多个读者可以安全地同时访问。

出于实际原因(可读性和可维护性),我不想让 InputManager 成为真正的不可变对象(即所有字段“最终”并在构造中初始化)。InputManager 将有许多数据结构(列表和映射),其中每个中的对象都有许多相互之间的循环引用。这些对象被构造为“真正的”不可变对象。我不希望 InputManager 有一个 14 个参数的构造函数,但我确实需要 InputManager 类在构造后提供问题空间的一致、只读视图。

我想要的是 Eric Lippert在这里讨论的“冰棒不变性”

我采用的方法依赖于使用所有变异方法的“包可见性”,并在单个包中执行所有可变操作(即 InputManager 的构造)。吸气剂都具有公开可见性。

就像是:

public final class InputManager {  // final to prevent making mutable subclasses 
    InputManager() { ... } //package visibility limits who can create one
        HashMap<String,InputA> lookupTable1;
        ...

    mutatingMethodA(InputA[] inputA) { //default (package visibility)
        //setting up data structures...
    }

    mutatingMethodB(InputB[] inputB) { //default (package visibility)
        //setting up data structures...
    }

    public InputA getSpecificInput(String param1) {
        ... //access data structures
        return objA; //return immutable object
    }
}
Run Code Online (Sandbox Code Playgroud)

总体思路,如果我还不够清楚,我将在单个线程中构造 InputManager,然后将其传递给将使用该对象执行并发工作的多个线程。我想尽可能地强制执行这个“两阶段”可变/不可变对象生命周期,而不是做一些太“可爱”的事情。寻找关于实现此目标的更好方法的评论或反馈,因为我确信这不是一个不常见的用例,但我也找不到支持它的设计模式。

谢谢。

Mar*_*nik 1

就我个人而言,我会坚持你简单而充分的方法,但如果你感兴趣,有一个可变同伴习语之类的东西。您编写一个具有修改器的内部类,同时重用封闭实例中的所有字段和获取器。

一旦你失去了可变同伴,它留下的封闭实例就真正是不可变的。