Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

safe publication of mutable object

I read several related questions, but none of them explains ways of safe publication of the Holder. I am still confused about example from Java Concurrency in Practice, section 3.5:

There is the class Holder:

public Holder {
    private int n;
    public Holder(int n) { this.n = n };
    public void assertSanity() {
        if(n != n)
             throw new AssertionError("This statement is false.");
    }
}

and its unsafe publication:

//unsafe publication
public Holder holder;
    public void initialize() {
        holder = new Holder(42);
    }

The AssertionError could be thrown and I agree. The authors write that it is because of unsafe publication, but on the other hand there is no answer: what would be the proper way of publication? They indicates 4 safe publication idioms, but I do not understand, why would they work in the above case:

To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:

  1. Initializing an object reference from a static initializer;
  2. Storing a reference to it into a volatile field or AtomicReference;
  3. Storing a reference to it into a final field of a properly constructed object;
  4. or Storing a reference to it into a field that is properly guarded by a lock.

I agree with 1&4, but have doubts why following publications would work:

//safe publication
public volatile Holder holder;

or

//safe publication
public final Holder holder;

volatile & final have impact only for the reference, not for the referenced object state, so I think the AssertionError would be still possible, right?

Instead of publication refinement, Authors show how to make the Holder immune for the unsafe publication, by:

private final int n;

I am curious if the following would also work? How is it connected with (effective) immutability?

private volatile int n;

It is my first question here, thank you for your help!

like image 996
88mariusz Avatar asked May 24 '18 09:05

88mariusz


People also ask

Are mutable objects thread safe?

A MessageService object is effectively immutable since its state can't change after its construction. So, it's thread-safe. Moreover, if MessageService were actually mutable, but multiple threads only have read-only access to it, it's thread-safe as well.

What is safe publication?

Safe publication makes all the values written before the publication visible to all readers that observed the published object. It is a great simplification over the JMM rules of engagement with regards to actions, orders and such.

Can mutable objects be changed?

The mutable objects can be changed to any value or state without adding a new object. Whereas, the immutable objects can not be changed to its value or state once it is created.


1 Answers

Actually I think that volatile is the simplest to explain here. Unsafe publication happens when operations can be reordered and volatile prevents that. I could explain more probably, but it's already explained far more accurate than I will do.

Basically underneath there will be proper memory barriers inserted that will prevent re-orderings, as explained here. Essentially, what volatile does, is that if a ThreadA reads a volatile update performed by ThreadB, it is guaranteed to also see all the updates that were done before that volatile write.

final makes things safe too and it's specifically written in the JLS.

But there are two cases here according to : Storing a reference to it into a final field of a properly constructed object.

So according to the JLS, this is safe publication:

class Holder {
    private final int n; // making final here
}

There are proper memory barriers inserted btw that prevent stores in the constructor to be re-ordered with publishing the reference itself.

What about this example?

static class Holder {

   private int n;

   public void setN(int n){
      this.n = n;
   }
}

And somewhere else:

 class Other {
    final Holder holder;
    Other(){
        holder = new Holder();
        holder.setN(12);
    }
 }

It looks like this is still safe publication according to this

like image 84
Eugene Avatar answered Oct 05 '22 20:10

Eugene