2

in Java Performance Tuning by Jack Shirazi it writes:

This means that access and update of variables are automatically synchronized (as long as they are not longs or doubles). If a method consists solely of a variable access or assignment, there is no need to make it synchronized for thread safety, and every reason not to do so for performance. Thread safety extends further to any set of statements that are accessing or assigning to a variable independently of any other variable values.

according to the description above, operations like flag = true is always atomic and does not need synchronize.

However, here comes another article that regards the flollowing circumstance as data race:


class DataRaceExample {
  static boolean flag = false;//w0
  static void raiseFlag() {
    flag = true;//w1
  }
  public static void main(String... args) {
    ForkJoinPool.commonPool().execute(DataRaceExample::raiseFlag);
    while (!flag);//r_i, where i ∈ [1, k), k may be infinite
    System.out.print(flag);//r
  }
}

and the author says:

Now, all executions have data races, because the flag is not volatile

It confused me a lot for the conflits between the two articles.

choxsword
  • 3,187
  • 18
  • 44

3 Answers3

4

Jack Shirazi is wrong.

Access and update of a primitive variable such as int is atomic, but not synchronized.

Because it is atomic, it can be made fully thread-safe by making it volatile. Without that, other threads running on a different core may see stale values, because the CPU cache hasn't been refreshed.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • 1
    He's not really wrong, he's unfortunately using non-standard, pre-JSR-133 terminology to describe read/write atomicity on primitive types. – Eric Dec 29 '19 at 21:47
2

The point that Jack Shirazi is trying to make is that non-volatile accesses to primitive types other than double and long are guaranteed to be performed atomically according to the JMM. Thus, synchronization is unnecessary to prevent, for example, torn reads and writes in the presence of concurrent accesses.

The confusion arises because his book predates JSR-133 and he uses terms like "automatically synchronized" which is not in line with modern notions of synchronization within the JMM.

Eric
  • 906
  • 7
  • 13
1

In your second example, the loop will either not run or run forever.

The reason for this is that the variable flag is read just once when it is first checked.

If flag is volatile, then it is read from memory each time. This allows another thread to change the value of flag and the loop will see it.

NomadMaker
  • 447
  • 1
  • 5
  • 9
  • If the read/write of boolean is **atomic** ,then the writes should always be **visible** to read in another thead. I know that cpu has cache, but if java guarantees visiblity of atomic operations, it should not be a problem here and no `volatile` is needed here. – choxsword Dec 29 '19 at 04:21
  • The trouble is that if flag isn't volatile it is read from memory just once. Even if it is changed from another thread, the loop doesn't reread the changes variable. – NomadMaker Dec 29 '19 at 04:27
  • do you agree that read of `flag` is atomic? If it's atomic, then every time it should read from the memory. That is to say, `volatile` is implicitly declared with variables except `long` or `double`. – choxsword Dec 29 '19 at 04:32
  • 1
    Yes, the read is atomic. However, that just means that a read from memory is completed in a guaranteed single action. It doesn't mean that it is always read from memory. – NomadMaker Dec 29 '19 at 04:36
  • 1
    But you're using a normal boolean rather than an AtomicBoolean. – NomadMaker Dec 29 '19 at 04:44
  • So the description of first article is completely wrong? Since the write of flag is only atomic, but not visible, so it's not synchronized and need a synchronization here? – choxsword Dec 29 '19 at 04:51
  • 1
    The variable flag _may_ be read only once. The specification does not require this behavior. – chrylis -cautiouslyoptimistic- Dec 29 '19 at 05:09