6

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!

88mariusz
  • 61
  • 3

2 Answers2

3

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

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • [good tip!](https://stackoverflow.com/questions/4449252/java-final-field-freeze-on-object-reachable-from-final-fields/4450951#4450951) Ok, let's say that `final` behavior of the `final Holder holder` is "propagated" (for freezing purpouse) to its content: `private int n`. It is actually answer for one of my questions. Thanks! Still I am confused about `volatile Holder holder` solution that [should not work](https://wiki.sei.cmu.edu/confluence/display/java/CON50-J.+Do+not+assume+that+declaring+a+reference+volatile+guarantees+safe+publication+of+the+members+of+the+referenced+object) AFAIU. – 88mariusz May 25 '18 at 12:30
  • @88mariusz I'll read that later, but this https://shipilev.net/blog/2014/safe-public-construction/ (and I trust Shipilev a lot more) is saying that this is perfectly fine for safe publication... I will read on that link later when I have the time – Eugene May 25 '18 at 12:37
  • @88mariusz had the time, read it again. this is really referring to different things. Look closely at the very first example there, *of course* that is not safely written, because there was not write to a volatile variable that some other thread observed and this is what happens-before is. Actually you can read a good answer here : https://stackoverflow.com/a/48339266/1059372 – Eugene May 29 '18 at 11:33
  • the example with the essential FinalWrapper _Since it is already too late to write to final field outside of constructor_ from [Shipilev](https://shipilev.net/blog/2014/safe-public-construction/) is to much for me. It makes the [previously good tip](https://stackoverflow.com/questions/4449252/java-final-field-freeze-on-object-reachable-from-final-fields/4450951#4450951) inapplicable to my question... I give up. Anyway, thank you @Eugene – 88mariusz Jun 02 '18 at 11:15
0

Make the integer volatile & synchronize it to a locking object with the thread in which you are concurring with.

This isn't the exact code but more of an idea for you to wrap your head around. No two things can operate on one thing at once. Thats what causes deadlocks in programs and even operating systems.

Class1:

public static final Object lock = new Object();
private Holder holder;
public abstract void method1(); //Assume these two go to different places
public abstract void method2(); //At different times w/ different implementations

Thread1:

public void method1() {
    synchronized(Class1.lock) {
        holder.assertMadness();
    }
}

Thread2:

public void method2() {
    synchronized(Class1.lock) {
        holder.assertMadness();
    }
}
Joe
  • 1,316
  • 9
  • 17
  • why make the lock static though?? – Jan Ossowski May 24 '18 at 09:36
  • You provided 2 safety mechanisms: instance-confinement & volatile keyword. My question is, how would the code behaves with each of the solutions solely? – 88mariusz May 24 '18 at 10:24
  • volatile acts as if nothing can touch it if something else is. As does synchronous. However, if two things are not synchronized together, and something tries to touch something already in use, it would cause a hang/deadlock on the something trying to touch the volatile variable that is already in use. Its a concept, and the documentation on it is slim to none, and whatever you do find, is cryptic because its a cryptic concept. Just sit there and think for a minute. No two things should ever I/O to one thing at the same time. Prevent it with these keywords. – Joe May 24 '18 at 15:01
  • @JanOssowski Its not necessary, but if you're using agents and trying to synchronize between two processes in the same JVM, it comes in handy. Although at that point you can still use reflection, but its easier – Joe May 24 '18 at 15:03
  • Joe, you just told, there would be a deadlock when use volatile and omit the synchronization, I really cannot imagine that. – 88mariusz May 25 '18 at 05:13
  • Not necessarily a deadlock, but it can hang – Joe May 25 '18 at 18:54