This is the second day of my participation in the August More Text Challenge

Happens-before principle for Java memory models

preface

  • The happens-before principle refers to the synchronization relationship between the thread’s local memory and the main memory. Only when the happens-before principle is met, data will be synchronized to the main memory when the thread memory changes, making the data change visible to other threads.

Instruction rearrangement

Instruction rearrangement introduction

  • The Java VM and CPU allow instructions to be executed in parallel as long as the semantics of execution do not change
a = b + c
x = y + z
Copy the code
  • The two statements above do not depend on each other semantically, so parallelism can exist.
a = x + y
d = a + z
Copy the code
  • The preceding two statements depend on each other and can be executed only after the first one is executed. Therefore, instruction rearrangement cannot be carried out in this case.

Multi-cpu instruction rearrangement problem

  • Let’s start with a piece of code like this
private volatile boolean a = false; private int b = 0; private int c = 0; A public void methodA(){this.b++; this.c++; this.a = true; } public void methodB(){while(this.a){}Copy the code
  • Here are two pieces of code executed by two threads. You can seemethodAThe three lines of code in the method are not actually interdependent, which can result in instruction rearrangement, as shown below. When this kind of reordering occurs, it is conceivable that the execution can cause error problems, and in some cases can be catastrophic.
public void methodA(){
        this.a = true;
        this.b++;
        this.c++;
    }
Copy the code

Happens-before eight principles

  • Single-thread happen-before principle: In the same thread, the previous actions happen-before the actions that follow.
  • Lock happens before: Unlock operation of the same lock happens before lock operation of the same lock.
  • The happen-before rule for volatile: Writes to a volatile variable happen-before any operations (including writes) to that variable.
  • The coincidentally -before transitivity principle: if A happens -before B, B happens -before C, then A happens -before C.
  • The happen-before rule for thread starts: start methods of the same thread happen-before other methods of this thread.
  • The coincidentally -before principle for thread interrupts: a call to the threadinterrupt method happens -before the code sent by the interrupted thread that detected the interrupt.
  • The happen-before principle of thread termination: All operations in a thread happen-before thread termination detection.
  • The happen-before principle for object creation: an object is initialized before its Finalize method is called.

Voletile’s instructions are rearranged

  • Let’s start with the following code
private volatile boolean a = false; private int b = 0; private int c = 0; A public void methodA(){this.b++; this.c++; this.a = true; } public void methodB(){while(this.a){}Copy the code
  • Using thevolatileThe keyword ensures that variables are synchronized to main memory during operations. When variables of A are synchronized, variables of B and C are synchronized to main memory. If the instruction is rearranged, and the values of b and C variables are not changed when variable A is changed to true, they will be read by other threads at this time, and abnormal problems will occur. sovolatileThe keyword also restricts the rearrangement of instructions before and after the variable modified.
public void methodA(){
        this.a = true;
        this.b++;
        this.c++;
    }
Copy the code

Command rearrangement for synchronised keyword

  • synchronisedThe keyword will ensure that the synchronized block is synchronized to main memory. Again, look at the following code:
private int a = 0; private int b = 0; private int c = 0; Public void methodA(){synchronised(this){int a1 = this.a; } int b1 = this.b; int c1 = this.c; } public void methodB(){this.b = b1; this.c = c1; synchronised(this){ this.a = a1; }}Copy the code
  • usesynchronisedKeyword reading reads all data from main memory into the local thread, while writing writes all data from the local thread into main memory. Therefore, if an instruction rearrangement occurs, other variables may be written after the synchronous code block is written or read before other variables are read, causing the problem that some variables cannot be read from main memory into the current thread copy and causing abnormal data. sosynchronisedIt also guarantees that there will be no reordering of instructions.
    int c1 = this.c;
    synchronised(this){
        int a1 = this.a;
    }
    int b1 = this.b;
Copy the code
    this.c = c1;
    synchronised(this){
        this.a = a1;
    }
    this.b = b1;
Copy the code

The tail down

  • How many events through the ages? Leisurely. The Yangtze River is still rolling.