0

In page 69 of Java Concurrency In Practice (Listing 4.11) they show the following class as thread safe example:

@ThreadSafe
public class SafePoint {
  @GuardedBy("this") private int x, y;

  private SafePoint(int[] a) {
    this(a[0], a[1]);
  }

  public SafePoint(SafePoint p) {
    this(p.get());
  }

  public SafePoint(int x, int y) {
    this.x = x;
    this.y = y;
  }

  public synchronized int[] get() {
    return new int[]{x, y};
  }

  public synchronized void set(int x, int y) {
    this.x = x;
    this.y = y;
  }

  public static void main(String[] args) {
    SafePoint point = new SafePoint(1, 2);
    System.out.println(Arrays.toString(point.get()));

  }
}

Note that constructor SafePoint(int x, int y) is public, and set non-final fields x and y without using the usual monitor this. Is it considered thread safe to set non-final fields in a constructor, without using the usual monitor that is otherwise used to guard these fields? If so then why? Normally we need to use the same monitor for any modification in order to assure visibility.

I noticed that the code in the site for this constructor is different, and does use the this as monitor for setting these fields:

public SafePoint(int x, int y) {
    this.set(x, y);
}

I would like to make it clear if this difference is a cosmetic one or fixes this issue?

dimo414
  • 47,227
  • 18
  • 148
  • 244
Shay
  • 464
  • 4
  • 14
  • You don't need to sync the fields inside the constructor. Nothing else can access the fields until the constructor has completed. – khelwood May 04 '19 at 10:28
  • What is "the code in the site"? – Erwin Bolwidt May 04 '19 at 10:29
  • @khelwood yes, but what guarantees that the values of this.x and this.y have actually been committed to "main memory"? Say thread A creates an instance of Safepoint, and shares that instance in a non-threadsafe manner with thread B. Do that a million times in a tight loop, and then what guarantees that thread B can't get an instance of Safepoint where the values of x and y haven't been written out yet? – Erwin Bolwidt May 04 '19 at 10:32
  • @ErwinBolwidt it can be found in the link I gave for the book, here I give direct one: http://jcip.net/listings.html – Shay May 04 '19 at 10:34
  • Thread A cannot share an instance with thread B until the instance has been constructed, which means its constructor has already completed. – khelwood May 04 '19 at 10:36
  • 2
    @khelwood yes it's constructor has completed but what guarantees that the values of x and y that it has written are visible to other threads? – Erwin Bolwidt May 04 '19 at 10:36
  • The other threads cannot have cached copies of an object's variables from before the object existed. – khelwood May 04 '19 at 10:39
  • 1
    @khelwood When an object's instance is constructed, its field values are initialized to the default values for each field type. It is perfectly possible, if the object reference is published with a data race, for other threads to see these default values rather than the values assigned to x and y by the constructor. This is explicitly mentioned in the Java language specification, section 17.5, where the semantics and benefits of final fields are explained: https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5 – Erwin Bolwidt May 04 '19 at 10:50
  • 2
    In conclusion: the code in the OP is not thread-safe if the object reference is published with a data race, but changing the constructor to `this.set(x, y);` fixes the issue as the `set` method is properly synchronized – Erwin Bolwidt May 04 '19 at 10:51

0 Answers0