Safe publication of local final references Safe publication of local final references multithreading multithreading

Safe publication of local final references


Although, admittedly, I'm not entirely sure that I got the actual point of your question, and (as pointed out in the comments) the issue is likely not really an issue in your particular case, maybe the relevant insights can be gained from a test/example

Considering the following class:

import java.util.concurrent.ExecutorService;class Unsafe{}class SafePublication{    private final ExecutorService mExecutor = null;    public void publish(final Unsafe unsafe)    {        mExecutor.execute(new Runnable()        {            @Override            public void run()            {                // do something with unsafe                System.out.println(unsafe);            }        });    }}

One can compile it, and obtain two .class files:

  • SafePublication.class
  • SafePublication$1.class for the inner class

Decompiling the class file for the inner class yields the following:

class SafePublication$1 implements java.lang.Runnable {  final Unsafe val$unsafe;  final SafePublication this$0;  SafePublication$1(SafePublication, Unsafe);    Code:       0: aload_0       1: aload_1       2: putfield      #1                  // Field this$0:LSafePublication;       5: aload_0       6: aload_2       7: putfield      #2                  // Field val$unsafe:LUnsafe;      10: aload_0      11: invokespecial #3                  // Method java/lang/Object."<init>":()V      14: return  public void run();    Code:       0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;       3: aload_0       4: getfield      #2                  // Field val$unsafe:LUnsafe;       7: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V      10: return}

One can see that for the final parameter, there is indeed a field introduced in this class. This field is val$unsafe, and it is a final field in the class file sense, and it is initialized in the constructor.

(This is not entirely equivalent to the second code snippet that you posted, because the second one contains two final fields, and they are both initialized with the same value. But regarding the issue of safe publication, the effect should be the same).


You left some important code out of your first example: The mExecutor object probably owns a BlockingQueue. The mExecutor.execute(r) call probably calls q.put(r) to add your task to the queue, and then sometime later, the worker thread calls r=q.take() to obtain the task before it can call r.run().

The put() and take() methods of the blocking queue will establish the same kind of "happens before" relationship between events in the two threads that would be established by one of the "safe publication" idioms.

Whatever the first thread updates in memory before calling q.put(r) is guaranteed to become visible to the second before the q.take() call returns.


The question seems to be partly answered by this answer:

Java multi-threading & Safe Publication

at least regarding "safe publication".

Now if the caller discards its reference the variable will be safe, because there exist no reference to the variable except in the final local variable.

And regarding the code examples - in my eyes both code snippets are equivalent. Introducing an additional local variable doesn't change the semantics, in both cases the compiler recognizes the reference as immutable and let you go with it.

EDIT - I am leaving this part to document my misinterpretation of the OP's question

To clarify - I take usage of final or volatile as granted in this example, so the proper memory barrier catering for the visibility of the object reference is there, the only point is the possible mutability of the non thread-safe object which cannot be guaranteed using memory barriers and actually has nothing to do with them. It can be taken care of either through proper synchronization or leaving only one reference to the content.

EDIT2 – after reading the OP’s comments

I have just looked at the JSR 133 FAQ - AFAIU a safe publication of a reference to object using a memory barrier doesn't guarantee that the unsychronized fields of the mentioned referenced object are visible too. Neither by final nor volatile.

If I am not misinterpreting this FAQ only synchronizing on the same monitor defines a “happens-before” relationship for all the writes one thread did before releasing the synchronizing lock and acquiring the lock on the same monitor by another thread.

I may be mistaken but it sounds to me as if also non-synchronized fields of the referenced object would be visible.

If using final keyword (like in your example where the parameter gets inserted as a final field) - only instance fields of the referenced object that themselves are final are guaranteed to be visible after the construction of the object ends.

But in the BlockingQueue (and as its implementation the LinkedBlockingQueue) I see no synchronized keyword whatsoever – it seems that it uses some very clever code to implement synchronization by using volatile fields, to me it doesn’t sound like a synchronization on a monitor in the sense described in JSR 133.

Which would mean that common blocking queues used by Executor do not guarantee visibility of non-final fields of your Unsafe instances. While the reference itself can be safely published using just the final keyword, the safe publishing of the fields this reference points to requires either the fields to be final, too, or a synchronization with a monitor shared by the writer and reader.

Don’t shoot the messenger :-).