3

Do I only need to mark a field volatile if multiple threads are reading it at the same time?

What about the scenario where Thread A changes the value of a field, and Thread B evaluates it after Thread A is guaranteed to have completed?

In my scenario, is there a happens-before relationship enforced (without the volatile keyword)?

AfterWorkGuinness
  • 1,780
  • 4
  • 28
  • 47
  • 1
    https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile Worth reading the whole thing. – pvg Jun 05 '16 at 20:20
  • 2
    if thread B executed A.join(), then reading the variable gives the value written by the thread A, and the variable needs not to be volatile. – Alexei Kaigorodov Jun 05 '16 at 20:25
  • 2
    How is it guaranteed, that thread A has finished, from the point of view of B? – hyde Jun 05 '16 at 21:24
  • The example I'm thinking of in more detail: Main thread has an ExecutorService which Runnable A is submitted to. Main thread examines a field on Runnable A that was changed while it was run asynch. We guarantee the thread is finished by calling get() on the Future it returned. – AfterWorkGuinness Jun 06 '16 at 02:02
  • the most straight-forward way to have happens-before without volatile is of course use of synchronized – Adrian Shum Jun 06 '16 at 04:14
  • Was going through internet and found this excellent article about volatile keyword with example. https://dzone.com/articles/java-volatile-keyword-0 – Kumar Saras Jan 19 '19 at 11:25

3 Answers3

5

You need the volatile keyword or some other synchronization mechanism to enforce the "happens before" relationship that guarantees visibility of the variable in threads other than the thread in which it was written. Without such synchronization, everything is treated as happening "at the same time", even if it doesn't by wall clock time.

In your particular example, one thing that may happen without synchronization is that the value written by thread A is never flushed from cache to main memory, and thread B executes on another processor and never sees the value written by thread A.

When you are dealing with threads, wall clock time means nothing. You must synchronize properly if you want data to pass between threads properly. There's no shortcut to proper synchronization that won't cause you headaches later on.

In the case of your original question, some ways proper synchronization can be achieved are by using the volatile keyword, by using synchronized blocks, or by having the thread that is reading the value of the variable join() the thread in which the variable is written.

Edit: In response to your comment, a Future has internal synchronization such that calling get() on a Future establishes a "happens before" relationship when the call returns, so that also achieves proper synchronization.

Warren Dew
  • 8,790
  • 3
  • 30
  • 44
  • 2
    Just one important clarification: you don’t need thread B to run on another processor to experience memory visibility issues (in other words, that can happen on single core CPUs too). One practical reason is JIT/Hotspot optimization resulting in code that keeps certain values in CPU registers without reading from or writing to the memory. You need proper *happens-before* relationships to indirectly tell the optimizer the limits. – Holger Jun 06 '16 at 19:08
  • @Holger Agreed. I was giving a simple example since sometimes people who aren't familiar with multithreading are skeptical about why synchronization is required when macroscopic elapsed times are involved. – Warren Dew Jun 06 '16 at 19:14
  • Does it mean a synchronized block causes everything written inside it be written to the main memory once the thread exits it? – Artem Novikov Jan 12 '17 at 15:59
  • @ArtemNovikov Information written in a synchronized block will be visible to code run later in another synchronized block if both are synchronized on the same object. That may or may not involve a write to main memory. My answer describes one example of how synchronization can go wrong, but it's not the only way. – Warren Dew Jan 13 '17 at 01:16
  • Any reference to the specification, please? – Artem Novikov Jan 14 '17 at 04:52
1

No, you don't need volatile...

is there a happens-before relationship enforced (without the volatile keyword)?

...but your code needs to do something to establish "happens-before."

There will be a happens-before relationship if (and only if) your code does something that the "Java Language Specification" (JLS) says will establish "happens-before."

What about the scenario where Thread A changes the value of a field, and Thread B evaluates it after Thread A is guaranteed to have completed?

Depends on what you mean by "guaranteed." If "guaranteed" means, "established happens-before," then your code will work as expected.

One way you can guarantee it is for thread B to call threadA.join(). The JLS guarantees that if thread B calls threadA.join(), then everything thread A did must "happen before" the join() call returns.

You do not need any of the shared variables to be volatile if thread B only accesses them after joining thread A.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57
0

You can chose one of available options to achieve the same purpose.

  1. You can use volatile to force all threads to get latest value of the variable from main memory.
  2. You can use synchronization to guard critical data
  3. You can use Lock API
  4. You can use Atomic variables

Refer to this documentation page on high level concurrency constructs.

Have a look at related SE questions:

Avoid synchronized(this) in Java?

What is the difference between atomic / volatile / synchronized?

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211