The realization of volatile memory semantics in deep parsing Java and the application of scene _java

Source: Internet
Author: User
Tags volatile

Realization of volatile memory semantics

Below, let's look at how JMM implements the memory semantics of volatile write/read.

We mentioned that the overweight sort is divided into compiler-reset sort and handler-reset. To implement volatile memory semantics, JMM restricts both types of reorder types. The following is a table of volatile collation jmm for the compiler:

For example, the last cell in the third line means that in the order of the program, when the first action is read or write for a generic variable, the compiler cannot reorder the two operations if the second action is volatile write.

From the table above we can see:

When the second operation is volatile write, no matter what the first action is, it cannot be reordered. This rule ensures that the actions before volatile write are not sorted by the compiler to volatile after writing.
When the first action is volatile read, no matter what the second operation is, it cannot be reordered. This rule ensures that volatile read operations are not sorted by the compiler before volatile read.
When the first operation is volatile write, the second operation is volatile read and cannot be reordered.
To implement the memory semantics of volatile, the compiler inserts a memory barrier into the instruction sequence when generating bytecode to prevent a particular type of processing from being sorted. For the compiler, it is almost impossible to find an optimal arrangement to minimize the total number of insertion barriers, so JMM adopts a conservative strategy. The following is a JMM memory barrier insertion strategy based on Conservative policies:

    • Inserts a storestore barrier at the front of each volatile write operation.
    • Inserts a storeload barrier behind each volatile write operation.
    • Inserts a loadload barrier behind each volatile read operation.
    • Inserts a loadstore barrier behind each volatile read operation.

The above memory barrier insertion strategy is very conservative, but it ensures that the correct volatile memory semantics are available on any processor platform, in any program.

Here is a schematic diagram of the sequence of instructions generated by the volatile insert memory barrier under the conservative strategy:

The Storestore barrier in the above figure ensures that all common writes before volatile are already visible to any processor before it is written. This is because the Storestore barrier will guarantee that all of the above ordinary writes are flushed to main memory before volatile write.

The interesting thing here is that volatile wrote the Storeload barrier behind it. The role of this barrier is to avoid volatile writes and volatile read/write operations that may follow. Because the compiler is often unable to accurately determine if a volatile is written, it is necessary to insert a storeload barrier (for example, after a volatile write method to return immediately). To ensure that the volatile memory semantics are implemented correctly, JMM is here to take a conservative approach: insert a storeload barrier behind each volatile write or in front of each volatile read. From the perspective of overall execution efficiency, JMM chose to insert a storeload barrier behind each volatile write. Because the common usage pattern of volatile write-read memory semantics is that a write thread writes a volatile variable, and multiple read threads read the same volatile variable. When the number of read threads is much larger than the write thread, the choice to insert the storeload barrier after volatile writes will result in a significant improvement in execution efficiency. From here we can see the JMM in the implementation of a feature: first of all to ensure correctness, and then to pursue the implementation of efficiency.

Here is a schematic diagram of the sequence of instructions generated by the volatile read insert memory barrier under Conservative policies:

The Loadload barrier in the above image is used to prevent the processor from reading the above volatile to the following normal read reordering. The Loadstore barrier is used to prevent the processor from reading the above volatile to the following normal write reordering.

The above volatile write and volatile read memory barrier insertion strategy is very conservative. In actual execution, as long as the memory semantics of volatile write-read are not changed, the compiler can omit unnecessary barriers according to the specific circumstances. Here's a sample code to illustrate:

Class Volatilebarrierexample {
  int A;
  volatile int v1 = 1;
  volatile int v2 = 2;

  void ReadAndWrite () {
    int i = v1;      The first volatile reads
    int j = v2;      The second volatile reads
    a = i + j;      General writing
    V1 = i + 1;     The first volatile write
    v2 = j * 2;     The second volatile write
  }

  ...          Other Methods
}

For the ReadAndWrite () method, the compiler can do the following optimizations when generating bytecode:

Note that the final storeload barrier cannot be omitted. Since the second volatile is written, the method immediately return. At this point, the compiler may not be able to accurately determine whether there will be volatile read or write, and for security reasons, the compiler will often insert a storeload barrier here.

The above optimization is for any processor platform, because different processors have different "tightness" of the processor memory model, the insertion of the memory barrier can also continue to optimize according to the specific processor memory model. Taking the x86 processor as an example, the other barriers will be omitted except for the final storeload barrier in the image above.

Volatile read and write in the previous conservative strategy, the x86 processor platform can be optimized to:

As mentioned earlier, the x86 processor will only reorder write-read operations. X86 does not reorder read-read, read-write, and write-write operations, so the memory barrier corresponding to these three types of operations is omitted from the x86 processor. In x86, JMM only need to insert a storeload barrier after volatile write to correctly implement the volatile write-read memory semantics. This means that in the x86 processor, the overhead of volatile writes is much greater than the overhead of volatile reading (because the storeload barrier overhead is higher).

JSR-133 why to enhance the memory semantics of volatile

In the old Java memory model before JSR-133, although volatile variables are not allowed to be reordered, the old Java memory model allows volatile variables to be reordered between normal variables. In the old memory model, the Volatileexample sample program might be reordered to perform the following sequence:

In the old memory model, when there is no data dependency between 1 and 2, it is possible to reorder between 1 and 2 (similar to 3 and 4). The result is that read thread B executes 4 o'clock and does not necessarily see a change to the shared variable that write thread A is performing 1 o'clock.

So in the old memory model, volatile's write-read has no release of the Monitor-the memory semantics it has. To provide a mechanism for communicating between threads that are lighter than monitor locks, the JSR-133 Expert Group decided to enhance the memory semantics of volatile: strictly restricting the reordering of volatile and ordinary variables by compilers and processors. Ensure that the volatile write-read and monitor release-get the same memory semantics. From the compiler reset collation and the processor memory barrier insertion strategy, the reordering of the volatile variable and the normal variable may break the memory semantics of the volatile, which is prohibited by the compiler reset collation and the processor memory barrier insertion policy.

Since volatile only guarantees that the read/write of a single volatile variable is atomic, the nature of the mutex execution of the monitor lock ensures that the execution of the entire critical area code is atomic. In functionality, monitor locks are more powerful than volatile, and volatile are more advantageous in scalability and performance. If the reader wants to use volatile in the program instead of the monitor lock, be careful.

Scenes using the volatile keyword

The Synchronized keyword is to prevent multiple threads from executing a piece of code at the same time, which can greatly affect program execution efficiency, while the volatile keyword performs better than synchronized in some cases. However, note that the volatile keyword cannot be substituted for the Synchronized keyword because the volatile keyword does not guarantee the atomic nature of the operation. Generally, the following 2 conditions must be used for volatile:

1 write operations on variables that do not depend on the current value

2 The variable is not included in the invariant with other variables

In fact, these conditions indicate that these valid values that can be written to the volatile variable are independent of the state of any program, including the current state of the variable.

In fact, my understanding is that the above 2 conditions require that the operation be atomic, to ensure that the program using the volatile keyword executes correctly at concurrency.

Here are a few scenarios for using volatile in Java.

1. Status Mark Quantity

Volatile Boolean flag = false;
 
while (!flag) {
 dosomething ();
}
 
public void Setflag () {
 flag = true;
}
 
Volatile Boolean inited = false;
Thread 1: Context
= Loadcontext (); 
Inited = true;   
 
Thread 2: While
(!inited) {sleep
()
}
dosomethingwithconfig (context);

2.double Check

Class singleton{
 Private volatile static Singleton instance = null;
  
 Private Singleton () {
   
 } public
  
 static Singleton getinstance () {
  if (instance==null) {
   synchronized ( Singleton.class) {
    if (instance==null)
     instance = new Singleton ();
   }
  }
  return instance
 }
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.