Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand JDK9 memory model?

I'm learning the JDK9 memory model.

After watching the speech Java Memory Model Unlearning Experience and reading the paper Using JDK 9 Memory Order Modes.

I'm confused about some concepts.

  1. Does opaque immediately guarantee the visibility?

  2. How to understand partial order and total order in the paper?

For the first question, the paper says

It is almost never a good idea to use bare spins waiting for values of variables. Use Thread.onSpinWait, Thread.yield, and/or blocking synchronization to better cope with the fact that "eventually" can be a long time, especially when there are more threads than cores on a system.

So if I write the code:

// shared variable I and VarHandle I_HANDLE which referred to I
public static int I = 0;

public static final VarHandle I_HANDLE;

// Thread-1
I_HANDLE.setOpaque(1);

// Thread-2
while((int) I_HANDLE.getOpaque() == 0){
}

The thread-2 eventually terminate but maybe after a long time?

If so, is there any minimal approach to guarantee thread-2 immediately see the modifying by thread-1? (Release/Acquire?volatile?)

like image 623
梁雨生 Avatar asked Jan 26 '21 06:01

梁雨生


People also ask

What do you understand by Java memory model?

The Java memory model describes how threads in the Java programming language interact through memory. Together with the description of single-threaded execution of code, the memory model provides the semantics of the Java programming language.

What is the JVM memory model and how does it work?

JVM Memory Structure. JVM creates various run time data areas in a heap. These areas are used during the program execution. The memory areas are destroyed when JVM exits, whereas the data areas are destroyed when the thread exits.

What is the memory model for threads?

The memory model stipulates that changes to the values of shared variables only need to be made visible to other threads when such a synchronization barrier is reached. Moreover, the entire notion of a race condition is defined over the order of operations with respect to these memory barriers.

How does Java memory work?

Java objects reside in an area called the heap. The heap is created when the JVM starts up and may increase or decrease in size while the application runs. When the heap becomes full, garbage is collected. During the garbage collection objects that are no longer used are cleared, thus making space for new objects.


1 Answers

There is no such thing like “immediately” for updates. Even electricity moves with a finite speed. Generally, asking for a perceivable effect within a particular time span is like asking for a particular execution time for an operation. Neither can be guaranteed, as they are properties of the underlying architecture which the JVM can’t change.

Practically, of course, JVM developers try to make the operations as fast as possible and all that matters to you, as a programmer, is that there is no faster alternative to opaque writes regarding inter-thread visibility of updates. The stronger access modes do not change how fast an update will become visible, they add additional constraints to reordering of reads and writes.

So in your example, the update will become visible as fast as the architecture and system load will allow1, but don’t ask for actual numbers. No-one can say how long it will take. If you need guarantees in terms of time quantities, you need a special (“real-time”) implementation that can give you additional guarantees beyond the Java Memory Model.


1 To name a practical scenario: thread 1 and 2 may compete for the same CPU. Thread 1 writes the value and continues to run for the operating system specific time before the task is switched (and it’s not even guaranteed that thread 2 is the next one). This implies that a rather long time may elapse, in both terms, wall clock time and thread 1’s progress after the write. Of course, other threads may also make a lot of progress on the other CPU cores in the meanwhile. But it’s also possible that thread 2’s polling before thread 1 commits the write is the cause of thread 1 not getting a chance to write the new value. That’s why you should mark such polling loops with onSpinWait or yield, to give the execution environment a chance to prevent such scenarios. See this Q&A for a discussion about the difference between the two.

like image 183
Holger Avatar answered Sep 30 '22 01:09

Holger