0

Consider 2 threads and an array int[] values. The first thread is performing:

synchronized (values) {
     values[i] = 58;
}

while the second thread is performing:

if (values[i] == 58) {
}

outside a synchronized block.

If the first thread first performs values[i]= 58, is it guaranteed that if the second threads executes slightly later, that the if of the second thread reads 58 even though the second thread reads values[i] outside a synchronized block?

insumity
  • 5,311
  • 8
  • 36
  • 64
  • How do you even ensure that "the second threads executes slightly later"? – Johannes Kuhn Mar 28 '20 at 00:02
  • 3
    It definitely is not guaranteed. See the Java Language Specification, [section 17.3](https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.3). – VGR Mar 28 '20 at 00:28
  • You seem to be asking if Java requires `sychronized` on both reads and writes, or if it's only required on the write. That question has already been answered: https://stackoverflow.com/questions/27120914/do-i-need-to-add-some-locks-or-synchronization-if-there-is-only-one-thread-writi – markspace Mar 28 '20 at 01:33

2 Answers2

2

If the first thread first performs values[i]= 58, is it guaranteed that if the second threads executes slightly later, that the if of the second thread reads 58 even though the second thread reads values[i] outside a synchronized block?

No

Synchronising this way does not stop other threads to perform any operation on the array simultaneously. However, other threads will be prevented to grab a lock on the array.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
1

Aforementioned behavior is not guaranteed. The guarantee of such a "visibility" is actually a subject of happens-before relationship:

The key to avoiding memory consistency errors is understanding the happens-before relationship. This relationship is simply a guarantee that memory writes by one specific statement are visible to another specific statement.

Happens-before relationship (according to JLS) can be achieved as such:

  1. Each action in a thread happens-before every action in that thread that comes later in the program's order.
  2. An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.
  3. A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.
  4. A call to start on a thread happens-before any action in the started thread.
  5. All actions in a thread happen-before any other thread successfully returns from a join on that thread.

So, in your particular case, you actually need either synchronization using a shared monitor or AtomicIntegerArray in order to make access to the array thread-safe; volatile modifier won't help as is, because it only affects the variable pointing to the array, not the array's elements (more detailed explanation).

nyarian
  • 4,085
  • 1
  • 19
  • 51