JMM memory model and Volatile keyword in Java

tags: java related  java

One: JMM

Java Memory Model, referred to as JMM, is the Java memory model, but JMM is different from JVM, which has a detailed block division such as a stack. Although JMM is called a model, it is essentially just a kind of emphasis on data (usually shared variables) read and writespecification, Is an abstract concept.

What is the standard of JMM? One thing to mention here is the thread, which is the meridian of the program, and JMM is closely related to the thread. If there is no thread constraint specification like JMM, then the variables in the thread will be used and littered. All sorts of random accesses are messy in memory. Therefore, from the perspective of program execution efficiency, the existence of the JMM specification is necessary.

And this kind of specification expands in detail, it is necessary to extend the eight major JMMinstruction, Instruction is an indivisible operation at the bottom of JMM.

  • read(Read): Read data from main memory
  • load(Load): Write the data read from the main memory into the working memory
  • user(Use): Read data from working memory to calculate
  • assign(Assignment): Re-assign the calculated value to the working memory
  • store(Storage): Write working memory data into main memory
  • write(Write): Assign the past variable value of store to the variable in the main memory
  • lock(Lock): lock the main memory variable, mark it as thread exclusive state
  • unlock(Unlock): Unlock the main memory variable, after unlocking, other threads can lock the variable


and related rules with eight instructions:

  • One of read and load, store and write operations is not allowed to appear alone. Even if you use read, you must load, and store must write

  • The thread is not allowed to discard its recent assign operation, that is, after the data of the work variable is changed, the main memory must be notified

  • Do not allow a thread to synchronize data without assign from working memory back to main memory

  • A new variable must be born in the main memory, and it is not allowed to directly use an uninitialized variable in the working memory.

  • Only one thread can lock a variable at a time. After multiple locks, you must perform the same number of unlocks to unlock

  • If a lock operation is performed on a variable, the value of this variable in all working memory will be cleared. Before the execution engine uses this variable, the value of the variable must be initialized by the load or assign operation again.

  • If a variable is not locked, it cannot be unlocked. Also cannot unlock a variable locked by other threads

  • Before unlocking a variable, the variable must be synchronized back to main memory



But there is a problem with JMM, that is, when multiple threads take values ​​from the main memory and load them into their own independent memory, when multiple threads work together on the same variable, the threads are invisible.
 In other words, when thread 1 and thread 2 take the shared variables into their own independent memory at the same time, thread 1 has a higher execution efficiency, and the variable operation is modified in a short period of time and finally submitted, while thread 2 does this It is not known that thread 1 has modified the shared variable, so that it has been executing independently. At this time, the variable version operated by thread 2 is out of touch with the main memory.

This kind of situation is called dirty read in the database, called branch merge conflict in git, and sometimes in the thread, it will sometimes cause thread insecurity.

In addition to locking, in order to solve such problems, the volatile keyword was derived.





Two: Volatile keywords


Volatile is a lightweight synchronization mechanism provided by JVM, which is characterized byEnsure visibilityNo guarantee of atomicityProhibit order rearrangement


1. Cases where visibility is not guaranteed:

package JMM;

import java.util.concurrent.TimeUnit;

public class jmmTest {
    private static int number = 0;

    public static void main(String[] args) {
        new Thread(()->{
            while (number==0){

            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        number=1;
        System.out.println(number);
    }


}

Operation result (the thread has not stopped after the number is modified):



2. Cases of ensuring visibility:

package JMM;

import java.util.concurrent.TimeUnit;

public class jmmTest {
    
    //Add the volatile keyword
    private static volatile int number = 0;

    public static void main(String[] args) {
        new Thread(()->{
            while (number==0){

            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        number=1;
        System.out.println(number);
    }


}

Operation result (thread stops after the number value is changed):



2. No guaranteeAtomicity

Of course, it cannot be said that atomicity is not guaranteed. For read and write operations that have a single structure, they are atomic and can be guaranteed, but if there are multiple operations like i++, atomicity is not guaranteed.


package JMM;

import java.util.concurrent.TimeUnit;

public class jmmTest {

    //Add the volatile keyword
    private static volatile int number = 0;

    public static void add(){
        number++;
    };

    public static void main(String[] args) {
        for (int i = 0; i <=20 ; i++) {
            new Thread(()->{
                while (number<=20000){
                    add();
                }
            }).start();
        }

        System.out.println(number);
    }

}

operation result:

(The 19957 here is not the only one. Each re-run may produce many different results. This is because volatile does not guarantee atomicity. In addition, the CPU execution speed is so fast that the use command of this thread has not ended. A read and load command may directly flush it down, causing the number++ operation to be too late to submit. And because threads cannot be interrupted when they perform tasks, they either succeed or fail at the same time. Once the thread is flushed, The default execution fails.)

And you can see that the number++ method does not just execute a single instruction at the bottom
 Of course, you can also use atomic level AtomicInteger to make up for it. At the same time, classes like AtomicInteger, AtomicBoolean, and AtomicLong have a large number of native keywords at the bottom, which are directly linked to the operating system and then atomically guaranteed.

package JMM;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class jmmTest {

    //Add the volatile keyword
    private static volatile AtomicInteger number = new AtomicInteger();
    ;

    public static void add(){
        number.getAndIncrement();
    };

    public static void main(String[] args) {
        for (int i = 1; i <=20 ; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000 ; j++) {
                    add();
                }
            }).start();
        }

    while (Thread.activeCount()>2){
        //The number of threads, except for main and gc, no other threads will stop polite
        Thread.yield();
    }

        System.out.println(number);
    }

}


Order rearrangement

Instruction rearrangement itself is a kind of operation optimization performed by the CPU, that is, when the program is transferred to the bottom layer, the original order is not necessarily retained.

For example:

int a = 90000;
int b = 1;
int c = 40;
int d = a+a;

The order in which the code is written is a, b, c, d, but it may be rearranged into b, a, c, d when it actually reaches the bottom layer. I personally think that when a is initialized because the value is relatively large, it may be Occupies more bits, and the creation time is relatively long, but the creation time of b is very short. If you want to make a variable whose creation time is only 1 second to wait for a variable whose creation time is one hour, then this arrangement is somewhat somewhat Delays things, so there is a rearrangement of instructions.
Of course, the rearrangement of instructions is not out of order, abcd may program bcad, and it is never possible to become dcba, because d depends on a, and the rearrangement of instructions needs to consider data dependence.


Volatile prohibits instruction rearrangement

The realization principle is to add one before and afterbarrier, The front door is not allowed to enter, and the back door is not allowed to go out, which naturally ensures that the instructions will not be rearranged.







Information reference:


JMM and the volatile keyword

Intelligent Recommendation

Concurrency (1): JMM memory model and volatile keyword

JMM memory model Each Java thread has a self-emptive memory. Operating data, read from the main memory, get a copy, write back to the main memory after the operation is completed. JMM may bring custod...

Volatile and JMM memory model

Volatile is a lightweight synchronization mechanism: Ensure visibility No guarantee of atomicity Prohibit order rearrangement JMM (Java Memory Model) Java memory model Three characteristics: Visibilit...

JMM memory model and volatile

JMM memory model The JMM memory model is the java memory model, also called the java thread memory model. First understand the concept of concurrency and parallelism. ​ Concurrency: It is a logical ar...

Java JMM and the volatile keyword

JMM JMM means JavaMemory model, Not JavaMemory layout, Not the so-called stack, heap, method area. Each Java thread has its ownWorking memory. Operation data, first read from the main memory, get a co...

Java memory model Jmm and volatile visibility

1.volatile Can guarantee the threadVisibility, When a thread is modifying our main memoryShared variableData can be seen by another thread. Note: The volatile keyword cannot guarantee atomicity. Featu...

More Recommendation

Java Memory Model (JMM) and volatile keywords

Java memory model structure diagram The Java thread memory model is similar to the CPU cache model and is based on the CPU cache model. The Java thread memory model is standardized to shield the diffe...

Deep understanding of Java memory model JMM and volatile

The Java Memory Model (JMM) is an abstract concept and does not really exist. It describes a set of specifications or rules through which various variables in the program (including instance fields an...

Java memory model (JMM) and volatile study notes

"In-depth understanding of JAVA virtual machine" The Java Memory Model (JMM) shields the memory access differences of various hardware and OS, and achieves consistency of access results on v...

Understand the JMM memory model and in-depth Volatile keyword principle

One, JMM memory model First look at the CPU multi-core concurrent cache architecture. Because the gap between CPU and memory data read and write is too large, a cache is added to alleviate this gap. T...

JUC concurrent programming VOLATILE keyword detailed explanation with JMM memory model

Volatile Volatile is a lightweight synchronization mechanism provided by JVM Volatile is a Java keyword for modifying variables Volatile only guarantees two points of JMM three major characteristics G...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top