javamultithreadingsafe-publication

Safe publication of local final references


I know that you can safely publish a non-thread safe object by writing the reference to a final or volatile field which will later be read by exactly one other thread, provided that upon publication, the thread that created the object discards the reference to it so it can no longer interfere with or unsafely observe the object's use in the other thread.

But in this example, there's no explicit final field, only final local variables. If the caller discards its reference to unsafe, is this safe publication?

void publish(final Unsafe unsafe) {
    mExecutor.execute(new Runnable() {
        public void run() {
            // do something with unsafe
        }
    }
}

I found a few Q&As, like this one, suggesting that final local variables are implicitly "copied" into anonymous classes. Does that mean that the above example is equivalent to this?

void publish(final Unsafe unsafe) {
    mExecutor.execute(new Runnable() {
        final Unsafe mUnsafe = unsafe;
        public void run() {
            // do something with mUnsafe
        }
    }
}

Edit for clarification:

Unsafe could be anything, but say it's something like this:

public class Unsafe {
    public int x;
}

And mExecutor is anything that satisfies the contract of Executor.


Solution

  • 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:

    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).