I am working on a problem when I need to load a large amount of input into a problem, and process these inputs to create a "problem space" (that is, create data structures that provide efficient access to inputs, etc.). Upon completion of this initialization, a multi-threaded process begins, which actively uses organized / processed input data in parallel.
For performance reasons, I do not want to block and synchronize all read operations in the parallel phase. What I really want is an immutable object, safe for multiple readers to access simultaneously.
For practical reasons (readability and maintainability), I do not want the InputManager to be a true immutable object (that is, all fields are “final” and initialized in the design). The InputManager will have many data structures (lists and maps), where each object has many circular links to each other. These objects are constructed as "true" immutable objects. I don't want to have a 14 argument constructor for the InputManager, but I need the InputManager class to provide a consistent read-only view of the problem space after it is built.
What I am going to do is the “Eskimo immutability,” as discussed by Eric Lippert here.
The approach that I take is based on using the "package visibility" of all mutation methods and performing all mutable actions (i.e., building the InputManager) in one package. Getters all have public visibility.
Sort of:
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 } }
The general idea, if I was not clear enough, is that I will create an InputManager in one thread, and then pass it to several threads that will do parallel work using the object. I want to ensure that this “two-phase” mutable / immutable life cycle of an object is fulfilled, and also possibly without doing anything too “sweet”. Looking for comments or feedback on the best ways to achieve this, as I'm sure this is not an unusual use case, but I cannot find a design template that supports it.
Thanks.