2

In the classic "Java concurrency in Practice" Brian Goetz uses the following snippet of code to demonstrate how to safely publish an object using a private constructor and a factory method:

public class SafeListener {
    private final EventListener listener;

    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        };
    }

    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

What I can't figure out yet is how this code achieves safe publication through a private constructor.

I am aware that a private constructor is used to prevent instantiation outside of the object but how does that apply to a thread rather than an object? A thread is not necessarily an object and I can't see what stops another thread from acquiring a reference to safe before the constructor finishes execution.

stratis
  • 7,750
  • 13
  • 53
  • 94
  • http://stackoverflow.com/questions/12611366/constructor-synchronization-in-java The answers given here discuss parts of your question. Constructors are indeed not synchronized and might execute the behaviour you described. The solution might be to put the instance initializing in a synchronized method instead, but I might be mistaken. – Joetjah Feb 04 '14 at 09:51

3 Answers3

2

Point here is to prevent escapement of this till constructor is finished. To this end, constructor is made private and factory method is provided which takes care of registering listener in external code, after object's constructor finished.

An example of thread-safe API.

Jason Law
  • 965
  • 1
  • 9
  • 21
Victor Sorokin
  • 11,878
  • 2
  • 35
  • 51
2

The constructor’s property of being private has nothing to do with the thread-safety. This is an example of the final field publication guaranty. In order for it to work, the this instance of the final field must not escape during the constructor, therefore the factory method takes care of constructing the holder instance first and registering the listener afterwards. It’s natural for applications of the factory pattern to have private constructors and public factory methods but that is not important to achieve the thread-safety here.

It’s all about how JIT and the HotSpot optimizer treat the code when performing the optimizations. They know what final or volatile fields are and what a constructor is. They will obey the limitations to the degree of optimization of such constructs. Most important, they ensure that all writes to an object you store in the final field and the write to the final field itself happen-before the constructor ends so that the final field stores happen-before any effect of the registerListener invocation in your example. Therefore, other threads can’t see the listener reference before its correct initialization.

Note that this is something you should rarely rely on. In your example, if the method registerListener of the EventSource is not thread-safe, still very bad things can happen. On the other hand, if it’s thread-safe, its thread-safety will apply to the listener constructed before the registration as well so the final field guaranty would not be needed.

Holger
  • 285,553
  • 42
  • 434
  • 765
1

how does that apply to a thread rather than an object? A thread is not necessarily an object and I can't see what stops another thread from acquiring a reference to safe before the constructor finishes execution.

A Thread is always an object in the java.lang.Thread sense, of course. The pattern should not be applied to a thread itself. Instead, it could be applied for cases where a new Thread has to be started "together" with the construction of an object. Starting the thread IN the constructor can allow the reference to the incompletely constructed object to escape. However, with this pattern, the newly constructed instance is trapped in the newInstance method until its construction is entirely complete.

(Or to put it that way: I can't imagine how another thread should acquire a reference to the safe instance before its construction is complete. Maybe you can give an example how how you think this might happen.)

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • So you are saying that if I do `myObject = newInstance(event)` the object is assigned only after it is completely constructed. However **while** it is constructed could another thread somehow step in and take control of `safe`? I believe it can but because `SafeListener safe` is being executed on the calling thread's stack (cause it's local until that thread returns it) it eventually cannot. Anyway I am a bit confused... – stratis Feb 04 '14 at 10:30
  • @Konos5: from the creating thread’s point of view everything always happens in the right order so the locally constructed object can’t be seen by others before registering the listener. However, due to certain optimizations, other threads may perceive the effects in a different order. The `final` field safe publication prevents certain optimizations. – Holger Feb 04 '14 at 10:40
  • 1
    Regarding *"**while** it is constructed could another thread somehow step in and take control of safe"* the answer is: No. When another thread enters this method, it it will not be able to access the *same* `safe` object. In the method, the `safe` object only exists on the stack. And each thread has its own stack. So when another thread enters this method, it will only have access to its OWN, new `safe` instance, but not to the one created by the first thread. – Marco13 Feb 04 '14 at 10:51
  • 1
    Right, there’s no need for thread-safety constructs for local objects. The important point is that threads going through the list of listeners registered to the `EventSource` might see the instance. And without thread safe constructs they may see it but not the right values of its instance fields. As said in my answer, if the event source/listener registration is thread-safe there’s no need for a special listener factory. – Holger Feb 04 '14 at 11:01
  • So from what I understand it all comes down to 2 main *threats*: **1) 'Rampage' threads** who whish to take control of 'safe' but they can't cause safe is created inside a method which means it is thread confined and thus each thread will have its own copy. **2) 'Nasty iterator' threads** looking through the listeners claiming the this instance of the final field but yet again they fail because safe won't have registered against the listeners before its constructor is complete and thus they won't be able to see it. – stratis Feb 04 '14 at 12:06