Java High concurrency III: Java memory model and thread safety detail _java

Source: Internet
Author: User
Tags visibility volatile

A lot of information on the web when describing the Java memory model, will introduce a main memory, and then each worker thread has its own working memory. The data is in main memory and there is a copy in the working RAM. There is a variety of atomic operations between working memory and main storage to synchronize.

The following figure comes from this blog

But because of the evolving Java version, the memory model has also changed. This article only covers some of the features of the Java memory model, whether it's a new memory model or an old memory model, and it looks clearer when these features are understood.

1. Atomic Sex

Atomicity means that an operation is not interrupted. Even when multiple threads are executing together, an operation is not disturbed by other threads once it has started.
The CPU's instructions are generally considered atomic, but the code we write is not necessarily an atomic operation.

such as i++. This operation is not atomic operation, basically divides into 3 operations, reads I, carries on +1, assigns the value to I.

Suppose there are two threads, and when the first thread reads I=1, there is not a +1 operation to switch to the second thread, at which point the second thread reads the I=1. Then two threads follow up on the +1 operation, then after the assignment back, I is not 3, but 2. Obviously, there is inconsistency in the data.

For example, the 32-bit JVM reads 64-bit long values and is not an atomic operation. Of course, a 32-bit JVM reading a 32-bit integer is an atomic operation.

2. Order of

When concurrency occurs, the execution of the program may be disorderly.

When the computer executes the code, it does not necessarily follow the order of the program.

Class Orderexample { 
 int a = 0; 
 Boolean flag = false; 
 public void writer () 
 { 
 a = 1; 
 Flag = true; 
 } 
 public void Reader () 
 { 
 if (flag) 
 { 
 int i = a +1; 
 } 
 }}

For example, the above code, two methods are called by two threads respectively. According to common sense, write thread should execute a=1 first, then execute flag=true. When reading a thread to read, i=2;

But because of a=1 and flag=true, there is no logical connection. So it is possible to execute the order upside down, it is possible to execute Flag=true first, then execute a=1. When flag=true, switch to read thread, at this time A=1 has not been executed, then read the thread will i=1.

Of course, this is not absolute. It is possible to have a disorderly order, which may not happen.

So why is there a disorderly sequence? This is to say from the CPU instructions, Java code is compiled, and finally converted to the remit code.

The execution of an instruction can be divided into many steps, assuming that the CPU instruction is divided into the following steps

    1. Take the indication IF
    2. Decoding and fetching register operand IDs
    3. Execution or valid address calculation EX
    4. Memory Access MEM
    5. Write back to WB

Let's say there are two instructions here.

In general, we would assume that the instructions are sequential, execute instruction 1 First, and then execute instruction 2. Assuming that each step consumes 1 CPU cycles, it is inefficient to execute the two instructions that consume 10 CPU cycles. In fact, the instructions are executed in parallel, of course, when the first instruction executes the IF, the second instruction is not able to do if, because the instruction register cannot be occupied simultaneously. So as shown in the figure above, two instructions are a relatively staggered way to execute in parallel. When instruction 1 executes an ID, instruction 2 executes if. This makes it more efficient to execute two instructions with only 6 CPU cycles.

In this way, let's take a look at how A=b+c's instructions are executed.

As shown in the illustration, the add operation has an idle (X) operation, because C is not read from memory when the x operation of the add in the diagram is added to B and C, and C is not read from memory when the mem operation completes. Here will be a doubt, at this time has not written back (WB) to R2, how will R1 and R1 added. That's because in the hardware circuit, a technology called "bypass" is used to read data directly from the hardware, so there is no need to wait for the WB to perform the Add. So there will be an idle (X) time in the add operation. In the SW operation, an idle (X) time is also available because the ex instruction cannot be performed at the same time as the add's ex instruction.

Let me give you a slightly more complicated example.

A=b+c
D=e-f

The corresponding instructions are shown below

The reason is similar to the above, it is not analyzed here. We find that there are a lot of x, wasted time cycles, and performance is affected. Is there any way to reduce the number of x?

We would like to use some operations to fill in the free time of x, because the add and the instructions above have data dependencies, we want to use some no data-dependent instructions to fill out these data dependencies due to the idle time.

We've changed the order of the instructions.

After changing the order of instruction, X is eliminated. The overall running time cycle has also been reduced.

Command rearrangement can make the assembly line smoother

Of course the principle of command rearrangement is not to break the semantics of serial programs, such as A=1,B=A+1, which will not be queued because the serialized serial results are different from the original.

Instruction rearrangement is just a way of optimizing the compiler or CPU, and this optimization creates the problem of starting the procedure in this chapter.

How to solve it? With the volatile keyword, this later series is introduced.

3. Visibility

Visibility means that when a thread modifies the value of a shared variable, other threads can immediately know about the change.

Visibility problems can occur in every aspect. For example, just said command rearrangement will also produce visibility problems, in addition to compiler optimization or some hardware optimization will produce visibility problems.

For example, a thread optimizes a shared value into memory, while another thread optimizes the shared value into the cache, and when the value in memory is modified, the value in the cache is unaware of the modification.

For example, some hardware optimization, the program in the same address to write multiple times, it will be considered unnecessary, only the last write, then the previous written data in other threads are not visible.

In summary, most of the visibility problems are due to optimization.

Next look at a Java virtual machine level of visibility issues

The problem comes from a blog

Package EDU.HUSHI.JVM;
 
/**
 * *
 @author -10
 * * */public
class Visibilitytest extends Thread {
 
 private boolean stop;
 
 public void Run () {
 int i = 0;
 while (!stop) {
  i++
 }
 System.out.println ("Finish loop,i=" + i);
 }
 
 public void StoPit () {
 stop = true;
 }
 
 public Boolean getstop () {return
 stop;
 }
 public static void Main (string[] args) throws Exception {
 Visibilitytest v = new Visibilitytest ();
 V.start ();
 
 Thread.Sleep (1000);
 V.stopit ();
 Thread.Sleep ();
 SYSTEM.OUT.PRINTLN ("Finish main");
 System.out.println (V.getstop ());
 }
 

The code is simple, the V thread has been constantly i++ in the while loop until the main thread calls the Stop method, changing the value of the stop variable in the V thread to stop the loop.
There is a problem when the seemingly simple code runs. This program can stop a thread from doing self augmentation in client mode, but in server mode it will be an infinite loop first. (JVM optimization is more in server mode)

Most of the 64-bit systems are in server mode and run in server mode:

Finish Main
True

Only the two sentences are printed, not the finish loop. However, the value of the stop can be found to be true.
The blogger uses tools to restore the program to assembly code

Here only a part of the assembly code, the red part of the loop, you can clearly see only in the 0x0193bf9d to do the stop verification, and the red part does not take the value of the stop, so the infinite loop.

This is the result of JVM optimizations. How to avoid it? As with the command rearrangement, use the volatile keyword.

If you add volatile, and then revert to assembly code, you'll find that every loop gets the value of the stop.

Next, look at some examples in the Java language specification

The figure above shows that the command rearrangement will result in different results.

The reason for the r5=r2 above is that r2=r1.x,r5=r1.x is optimized directly to R5=R2 at compile time. Finally, the results are different.

4. Happen-before

    1. Program Order principle: The serial nature of semantics in a thread
    2. Volatile rule: Write the volatile variable, which first occurs in the read, which guarantees the visibility of the volatile variable
    3. Lock rule: Unlock (unlock) must occur before lock (lock)
    4. Transitivity: A prior to b,b C, then a must precede C
    5. The thread's start () method is preceded by each of its actions
    6. All operations of a thread precede the end of the thread (Thread.Join ())
    7. Thread interrupts (interrupt ()) prior to the code of the interrupted thread
    8. The execution of an object's constructor ends before the Finalize () method
    9. These principles ensure that the semantics of the rearrangement are consistent.

5. The concept of thread safety

Refers to a function, function library in a multithreaded environment is invoked, can correctly handle the local variables of each thread, so that the program function correctly completed.

Like the i++ example of the beginning,

Will cause the thread to be unsafe.

For more information on thread safety use, refer to the blog that you wrote previously, or focus on the follow-up series, and talk about the relevant content

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.