How do I create a thread-safe write-once read-many value in Java?
- by Software Monkey
This is a problem I encounter frequently in working with more complex systems and which I have never figured out a good way to solve. It usually involves variations on the theme of a shared object whose construction and initialization are necessarily two distinct steps. This is generally because of architectural requirements, similar to applets, so answers that suggest I consolidate construction and initialization are not useful.
By way of example, let's say I have a class that is structured to fit into an application framework like so:
public class MyClass
{
private /*ideally-final*/ SomeObject someObject;
MyClass() {
someObject=null;
}
public void startup() {
someObject=new SomeObject(...arguments from environment which are not available until startup is called...);
}
public void shutdown() {
someObject=null; // this is not necessary, I am just expressing the intended scope of someObject explicitly
}
}
I can't make someObject final since it can't be set until startup() is invoked. But I would really like it to reflect it's write-once semantics and be able to directly access it from multiple threads, preferably avoiding synchronization.
The idea being to express and enforce a degree of finalness, I conjecture that I could create a generic container, like so:
public class WoRmObject<T>
{
private T object;
WoRmObject() {
object=null;
}
public WoRmObject set(T val) { object=val; return this; }
public T get() { return object; }
}
and then in MyClass, above, do:
private final WoRmObject<SomeObject> someObject;
MyClass() {
someObject=new WoRmObject<SomeObject>();
}
public void startup() {
someObject.set(SomeObject(...arguments from environment which are not available until startup is called...));
}
Which raises some questions for me:
Is there a better way, or existing Java object (would have to be available in Java 4)?
Is this thread-safe provided that no other thread accesses someObject.get() until after it's set() has been called. The other threads will only invoke methods on MyClass between startup() and shutdown() - the framework guarantees this.
Given the completely unsynchronized WoRmObject container, it is ever possible under either JMM to see a value of object which is neither null nor a reference to a SomeObject? In other words, does has the JMM always guaranteed that no thread can observe the memory of an object to be whatever values happened to be on the heap when the object was allocated.