Concurrent programming series – Volatile details

preface

During the interview process, the use of volatile is a common question point. The interviewer’s main question is about the visibility of volatile to shared variables

  • What does the volatile keyword do
  • How volatile implements visibility (memory barriers)
  • I++ can’t guarantee atomicity
  • Application scenarios of volatile
  • What is the Java Memory model

Introduction to the

Volatile is known as lightweight Synchronize and has a lower runtime cost than Synchronize. We know that Volatile provides visibility to shared variables and forbade instruction reordering. Today we will look at how Volatile implements these functions. First let’s take a look at the Java memory model.

The memory model

JMM itself does not exist. It is a concept for us to easily understand abstracts. It is a set of rules and specifications that define the access mode of each variable in the program. Each thread has its own working memory, and all operations on variables must be performed from main memory. Operations on variables cannot be performed directly in main memory, and threads cannot access the working memory of other threads. (PS, the processor does not directly communicate in memory, but first reads the data in memory into memory cache (hardware is called CPU L1,L2 cache) for operation, the reason for doing so is to improve speed)

Introduced problems

If a variable is cached on each CPU (read into its own working memory in the case of multiple threads) and the cache is inconsistent, take a look at this example, as shown in the figure below

In the example above, the concurrency of I can be solved in the following two ways

  • By adding a Lock on the bus to solve the problem
  • Cache consistency protocol

Memory visibility of volatile variables is achieved through a memory barrier, which is essentially a set of CPU instructions. When we write to a volatile declared variable, the UNDERLYING JVM prefixes the write to a volatile shared variable with a lock directive. Let’s look at the lock instruction.

The lock instruction

In the early pentium and Inter processors, the lock prefix would cause the processor to execute a lock# signal to lock the bus. Other CPU reads and writes to the memory would be blocked until the lock was released. Later processors gradually used the Cache Consistency Protocol (MESI) to replace this approach. Because other cpus cannot access the memory during bus locking, the efficiency is low.

Cache consistency protocol

Usually we use most of the calculator cache consistency protocol are sniffing, all memory of the transmission is in a Shared bus, all the CPU can see a bus, in addition to the CPU continuously sniff the data on the bus for data exchange, track may also be other CPU cache do, as long as the CPU processor to write data into the memory, Other CPU processors will set the cache segment in their own memory to invalid state, when used to read from the main memory. A volatile variable is a mechanism that allows each thread to obtain its latest value.

Memory barrier effect

Memory barriers have two functions. (If we use volatile variables, read barriers are inserted on reads, invalidating the cache and allowing the data to be read from main memory. Insert write barrier before write instruction to write the latest data written to cache to main memory)

  1. Instructions that use the memory barrier first must be executed, and those that follow must be executed later
  2. Memory can be seen

happen-before

The happen-before relationship is the mechanism in the Java memory model that ensures visibility of multithreaded operations. In short, what determines whether a variable is visible to you is a vague definition of visibility, expressed as follows

  • Every operation performed within the thread guarantees the operation after happening-before, which guarantees the order rules for program writing
  • For volatile variables, for writes, be sure to happen-before on subsequent reads of the variable (so that when we write to volatile variables, the cache values of other variables are invalid)
  • The object is built, ensuring happen-before Fiazlize starts action

For example

//x and y are non-volatile variables, and z is volatile
x = 2;        //语句1
y = 0;        //语句2
z = true;     //语句3
x = 4;         //语句4
y = -1;       5 / / statement
Copy the code

Since flag variables are volatile, statements 3 are not placed before statements 1 and 2, and statements 3 is not placed after statements 4 and 5 during instruction reordering. When executing 3, 1,2 must be executed and the results of 1,2 must be visible to 3, 4, and 5

Volatile Application Scenario

  • Double check of singleton model (ps see the summary of this blogger’s singleton pattern series for details)

The giant shoulder

zhuanlan.zhihu.com/p/137193948

gossip

If you feel helpful, please click “like” to pay attention, which will be a great encouragement to me ~, the official account has its own series of articles, you need to pay attention to the personal official account programmer Fly, I hope we can grow up together.