2

I need some memory model advice.

As we know volatile write and subsequent volatile read have happens-before relationships. Also we know that constructors are not synchronized and there is no hb between constructor returns and using fields initialization (except final fields). Now consider the following code:

public class MyClass{
    public volatile String str1;
    public volatile String str2;

    public MyClass(String str1, String str2){
        this.str1 = str1;
        this.str2 = str2;
    }

    public void use(){
        System.out.println(str1 + str2);
    }
}

usage:

public volatile MyClass mc = null;

Thread(() -> {
    mc = new MyClass("str1", "str2"));
}).start();

Thread(() -> {
    If(mc != null)
       mc.use;       //Is it guaranteed that str1str2 will be printed if we get here?
}).start();

Is it guaranteed that if the thread discovers mc != null then str1str2 will always be printed?

I think it is guaranteed by the JMM because here in mc = new MyClass("str1", "str2")); writing to mc and writing to str1 and str2 are in happens-before relationship. This is because writing to str1/str2 are performed according to inter-thread semantic so they are in program order. So we have writing to mc hb reading mc so "str1str2" will always be printed.

Also if we make fields str1/str2 non-volatile there will be no such guarantee anymore.

Is my judgement correct? Can you please expand?

Some Name
  • 8,555
  • 5
  • 27
  • 77
  • Possible duplicate of [If Thread B wishes to see changes Thread A makes, can only the last change be to a volatile variable as opposed to all?](https://stackoverflow.com/q/52509663/5221149) – Andreas Sep 30 '18 at 18:41
  • Even if `str1` and `str2` were not `volatile`, the simple fact of `mc` being `volatile` means that output will always be "str1str2", if there is any output at all. See answer in link above for why. – Andreas Sep 30 '18 at 18:43
  • @Andreas Not quite clear how you imply this. Let me try to go step by step. There is a `hb` writing to a volatile and subsequent read from volatile. But there is no hb between writing to `str2` in constructor and writing to `mc`. – Some Name Sep 30 '18 at 18:46
  • 1
    Sure there is: *"If x and y are actions of the same thread and x comes before y in program order, then hb(x, y)"* --- So `hb( this.str1 = str1 , mc = new MyClass )`, and `volatile` ensures that `hb( mc = new MyClass , mc.use() )`, and you also have `hb( mc.use() , println(str1 + str2) )`, which means `hb( this.str1 = str1 , println(str1 + str2) )`, exactly the same sequence of events as in the duplicate. – Andreas Sep 30 '18 at 18:47
  • @Andreas thanks, understood. – Some Name Sep 30 '18 at 18:50
  • 1
    The point is that mc will only != null when the constructor has successfuly finished. – PowerStat Oct 03 '18 at 11:55

0 Answers0